AscEmu
OpenSource WoW Emulator
Loading...
Searching...
No Matches
Spell Class Reference

#include <Spell.hpp>

Inheritance diagram for Spell:
[legend]
Collaboration diagram for Spell:
[legend]

Classes

struct  HitAuraEffect
 
struct  HitSpellEffect
 
struct  MissSpellEffect
 

Public Member Functions

 Spell (Object *_caster, SpellInfo const *_spellInfo, bool _triggered, Aura *_aura)
 
 ~Spell ()
 
SpellCastResult prepare (SpellCastTargets *targets)
 
void castMe (const bool doReCheck)
 
void handleHittedTarget (const uint64_t targetGuid, uint8_t effIndex)
 
void handleHittedEffect (const uint64_t targetGuid, uint8_t effIndex, int32_t effDamage, bool reCheckTarget=false)
 
void handleMissedTarget (SpellTargetMod const missedTarget)
 
void handleMissedEffect (SpellTargetMod const missedTarget, bool reCheckTarget=false)
 
void finish (bool successful=true)
 
void update (unsigned long timePassed)
 
void cancel ()
 
int32_t calculateEffect (uint8_t effIndex)
 
void calculateJumpSpeeds (Unit *unitCaster, SpellInfo const *spellInfo, uint8_t i, float dist, float &speedXY, float &speedZ)
 
virtual SpellCastResult canCast (const bool secondCheck, uint32_t *parameter1, uint32_t *parameter2)
 
SpellCastResult checkPower ()
 
void sendCastResult (SpellCastResult result, uint32_t parameter1=0, uint32_t parameter2=0)
 
void sendChannelUpdate (const uint32_t time, const uint32_t diff=0)
 
int32_t getFullCastTime () const
 
int32_t getCastTimeLeft () const
 
uint32_t getPowerCost () const
 
ObjectgetCaster () const
 
UnitgetUnitCaster () const
 
PlayergetPlayerCaster () const
 
GameObjectgetGameObjectCaster () const
 
ItemgetItemCaster () const
 
void setItemCaster (Item *itemCaster)
 
bool wasCastedinDuel () const
 
bool hasTarget (const uint64_t &_guid, std::vector< uint64_t > *tmpGuidMap)
 
ItemgetItemTarget () const
 
void setUnitTarget (Unit *_unit)
 
UnitgetUnitTarget () const
 
PlayergetPlayerTarget () const
 
GameObjectgetGameObjectTarget () const
 
CorpsegetCorpseTarget () const
 
void unsetAllTargets ()
 
void setTargetConstraintCreature (Creature *_creature)
 
CreaturegetTargetConstraintCreature () const
 
void setTargetConstraintGameObject (GameObject *_gameobject)
 
GameObjectgetTargetConstraintGameObject () const
 
LocationVector getDestination ()
 
LocationVector getSource ()
 
SpellInfo constgetSpellInfo () const
 
bool hasAttribute (SpellAttributes _attribute) const
 
bool hasAttributeEx (SpellAttributesEx _attribute) const
 
bool hasAttributeExB (SpellAttributesExB _attribute) const
 
bool hasAttributeExC (SpellAttributesExC _attribute) const
 
bool hasAttributeExD (SpellAttributesExD _attribute) const
 
bool hasAttributeExE (SpellAttributesExE _attribute) const
 
bool hasAttributeExF (SpellAttributesExF _attribute) const
 
bool hasAttributeExG (SpellAttributesExG _attribute) const
 
void resetSpellInfoOverride ()
 
AuragetTriggeredByAura () const
 
int8_t getUsedComboPoints () const
 
void addUsedSpellModifier (AuraEffectModifier const *aurEff)
 
void removeUsedSpellModifier (AuraEffectModifier const *aurEff)
 
void takeUsedSpellModifiers ()
 
void setForceCritOnTarget (Unit const *target)
 
int32_t getDuration ()
 
float_t getEffectRadius (uint8_t effectIndex)
 
void spellEffectNotImplemented (uint8_t effectIndex)
 
void spellEffectNotUsed (uint8_t effectIndex)
 
void spellEffectInstantKill (uint8_t effectIndex)
 
void spellEffectSchoolDMG (uint8_t effectIndex)
 
void spellEffectDummy (uint8_t effectIndex)
 
void spellEffectTeleportUnits (uint8_t effectIndex)
 
void spellEffectApplyAura (uint8_t effectIndex)
 
void spellEffectEnvironmentalDamage (uint8_t effectIndex)
 
void spellEffectPowerDrain (uint8_t effectIndex)
 
void spellEffectHealthLeech (uint8_t effectIndex)
 
void spellEffectHeal (uint8_t effectIndex)
 
void spellEffectBind (uint8_t effectIndex)
 
void spellEffectQuestComplete (uint8_t effectIndex)
 
void spellEffectWeapondamageNoschool (uint8_t effectIndex)
 
void spellEffectResurrect (uint8_t effectIndex)
 
void spellEffectAddExtraAttacks (uint8_t effectIndex)
 
void spellEffectDodge (uint8_t effectIndex)
 
void spellEffectParry (uint8_t effectIndex)
 
void spellEffectBlock (uint8_t effectIndex)
 
void spellEffectCreateItem (uint8_t effectIndex)
 
void spellEffectWeapon (uint8_t effectIndex)
 
void spellEffectDefense (uint8_t effectIndex)
 
void spellEffectPersistentAA (uint8_t effectIndex)
 
void spellEffectSummon (uint8_t effectIndex)
 
void spellEffectSummonWild (uint8_t effectIndex)
 
void spellEffectSummonGuardian (uint8_t effectIndex, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties_, LocationVector &v)
 
void spellEffectSummonTemporaryPet (uint8_t effectIndex, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties_, LocationVector &v)
 
void spellEffectSummonTotem (uint8_t effectIndex, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties, LocationVector &v)
 
void spellEffectSummonPossessed (uint8_t effectIndex, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties_, LocationVector &v)
 
void spellEffectSummonCompanion (uint8_t effectIndex, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties_, LocationVector &v)
 
void spellEffectSummonVehicle (uint8_t effectIndex, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties_, LocationVector &v)
 
void spellEffectLeap (uint8_t effectIndex)
 
void spellEffectEnergize (uint8_t effectIndex)
 
void spellEffectWeaponDmgPerc (uint8_t effectIndex)
 
void spellEffectTriggerMissile (uint8_t effectIndex)
 
void spellEffectOpenLock (uint8_t effectIndex)
 
void spellEffectTransformItem (uint8_t effectIndex)
 
void spellEffectApplyGroupAA (uint8_t effectIndex)
 
void spellEffectLearnSpell (uint8_t effectIndex)
 
void spellEffectSpellDefense (uint8_t effectIndex)
 
void spellEffectDispel (uint8_t effectIndex)
 
void spellEffectDualWield (uint8_t effectIndex)
 
void spellEffectSkillStep (uint8_t effectIndex)
 
void spellEffectAddHonor (uint8_t effectIndex)
 
void spellEffectSpawn (uint8_t effectIndex)
 
void spellEffectSummonObject (uint8_t effectIndex)
 
void spellEffectEnchantItem (uint8_t effectIndex)
 
void spellEffectEnchantItemTemporary (uint8_t effectIndex)
 
void spellEffectTameCreature (uint8_t effectIndex)
 
void spellEffectSummonPet (uint8_t effectIndex)
 
void spellEffectLearnPetSpell (uint8_t effectIndex)
 
void spellEffectWeapondamage (uint8_t effectIndex)
 
void spellEffectOpenLockItem (uint8_t effectIndex)
 
void spellEffectProficiency (uint8_t effectIndex)
 
void spellEffectSendEvent (uint8_t effectIndex)
 
void spellEffectPowerBurn (uint8_t effectIndex)
 
void spellEffectThreat (uint8_t effectIndex)
 
void spellEffectClearQuest (uint8_t effectIndex)
 
void spellEffectForceCast (uint8_t effectIndex)
 
void spellEffectTriggerSpell (uint8_t effectIndex)
 
void spellEffectApplyRaidAA (uint8_t effectIndex)
 
void spellEffectPowerFunnel (uint8_t effectIndex)
 
void spellEffectHealMaxHealth (uint8_t effectIndex)
 
void spellEffectInterruptCast (uint8_t effectIndex)
 
void spellEffectDistract (uint8_t effectIndex)
 
void spellEffectPickpocket (uint8_t effectIndex)
 
void spellEffectAddFarsight (uint8_t effectIndex)
 
void spellEffectUseGlyph (uint8_t effectIndex)
 
void spellEffectHealMechanical (uint8_t effectIndex)
 
void spellEffectSummonObjectWild (uint8_t effectIndex)
 
void spellEffectScriptEffect (uint8_t effectIndex)
 
void spellEffectSanctuary (uint8_t effectIndex)
 
void spellEffectAddComboPoints (uint8_t effectIndex)
 
void spellEffectCreateHouse (uint8_t effectIndex)
 
void spellEffectDuel (uint8_t effectIndex)
 
void spellEffectStuck (uint8_t effectIndex)
 
void spellEffectSummonPlayer (uint8_t effectIndex)
 
void spellEffectActivateObject (uint8_t effectIndex)
 
void spellEffectBuildingDamage (uint8_t effectIndex)
 
void spellEffectEnchantHeldItem (uint8_t effectIndex)
 
void spellEffectSetMirrorName (uint8_t effectIndex)
 
void spellEffectSelfResurrect (uint8_t effectIndex)
 
void spellEffectSkinning (uint8_t effectIndex)
 
void spellEffectCharge (uint8_t effectIndex)
 
void spellEffectKnockBack (uint8_t effectIndex)
 
void spellEffectKnockBack2 (uint8_t effectIndex)
 
void spellEffectDisenchant (uint8_t effectIndex)
 
void spellEffectInebriate (uint8_t effectIndex)
 
void spellEffectFeedPet (uint8_t effectIndex)
 
void spellEffectDismissPet (uint8_t effectIndex)
 
void spellEffectReputation (uint8_t effectIndex)
 
void spellEffectSummonObjectSlot (uint8_t effectIndex)
 
void spellEffectDispelMechanic (uint8_t effectIndex)
 
void spellEffectSummonDeadPet (uint8_t effectIndex)
 
void spellEffectDestroyAllTotems (uint8_t effectIndex)
 
void spellEffectDurabilityDamage (uint8_t effectIndex)
 
void spellEffectDurabilityDamagePCT (uint8_t effectIndex)
 
void spellEffectResurrectNew (uint8_t effectIndex)
 
void spellEffectAttackMe (uint8_t effectIndex)
 
void spellEffectSkinPlayerCorpse (uint8_t effectIndex)
 
void spellEffectSkill (uint8_t effectIndex)
 
void spellEffectApplyPetAA (uint8_t effectIndex)
 
void spellEffectDummyMelee (uint8_t effectIndex)
 
void spellEffectStartTaxi (uint8_t effectIndex)
 
void spellEffectPlayerPull (uint8_t effectIndex)
 
void spellEffectReduceThreatPercent (uint8_t effectIndex)
 
void spellEffectSpellSteal (uint8_t effectIndex)
 
void spellEffectProspecting (uint8_t effectIndex)
 
void spellEffectApplyFriendAA (uint8_t effectIndex)
 
void spellEffectApplyEnemyAA (uint8_t effectIndex)
 
void spellEffectRedirectThreat (uint8_t effectIndex)
 
void spellEffectPlayMusic (uint8_t effectIndex)
 
void spellEffectForgetSpecialization (uint8_t effectIndex)
 
void spellEffectKillCredit (uint8_t effectIndex)
 
void spellEffectRestorePowerPct (uint8_t effectIndex)
 
void spellEffectTriggerSpellWithValue (uint8_t effectIndex)
 
void spellEffectApplyOwnerAA (uint8_t effectIndex)
 
void spellEffectCreatePet (uint8_t effectIndex)
 
void spellEffectTeachTaxiPath (uint8_t effectIndex)
 
void spellEffectDualWield2H (uint8_t effectIndex)
 
void spellEffectEnchantItemPrismatic (uint8_t effectIndex)
 
void spellEffectCreateItem2 (uint8_t effectIndex)
 
void spellEffectMilling (uint8_t effectIndex)
 
void spellEffectRenamePet (uint8_t effectIndex)
 
void spellEffectRestoreHealthPct (uint8_t effectIndex)
 
void spellEffectLearnSpec (uint8_t effectIndex)
 
void spellEffectActivateSpec (uint8_t effectIndex)
 
void spellEffectActivateRunes (uint8_t effectIndex)
 
void spellEffectJumpTarget (uint8_t effectIndex)
 
void spellEffectJumpBehindTarget (uint8_t effectIndex)
 
void FillSpecifiedTargetsInArea (float srcx, float srcy, float srcz, uint32_t ind, uint32_t specification)
 
void FillSpecifiedTargetsInArea (uint32_t i, float srcx, float srcy, float srcz, float range, uint32_t specification)
 
void FillAllTargetsInArea (uint32_t i, float srcx, float srcy, float srcz, float range)
 
void FillAllTargetsInArea (float srcx, float srcy, float srcz, uint32_t ind)
 
void FillAllTargetsInArea (LocationVector &location, uint32_t ind)
 
void FillAllFriendlyInArea (uint32_t i, float srcx, float srcy, float srcz, float range)
 
uint64_t GetSinglePossibleEnemy (uint32_t i, float prange=0)
 
uint64_t GetSinglePossibleFriend (uint32_t i, float prange=0)
 
bool GenerateTargets (SpellCastTargets *store_buff)
 
void FillTargetMap (uint32_t)
 
void HandleTargetNoObject ()
 
uint8_t DidHit (uint32_t effindex, Unit *target)
 
void castMeOld ()
 
uint8_t CanCast (bool)
 
void HandleTeleport (LocationVector position, uint32_t mapid, Unit *Target)
 
void DetermineSkillUp ()
 
void AddTime (uint32_t type)
 
uint32_t getState () const
 
void SendLogExecute (uint32_t damage, uint64_t &targetGuid)
 
void SendInterrupted (uint8_t result)
 
void SendResurrectRequest (Player *target)
 
void SendTameFailure (uint8_t failure)
 
void HandleAddAura (uint64_t guid)
 
void CreateItem (uint32_t itemId)
 
void ApplyAreaAura (uint8_t effectIndex)
 
void SpellEffectInstantKill (uint8_t effectIndex)
 
void SpellEffectSchoolDMG (uint8_t effectIndex)
 
void SpellEffectTeleportUnits (uint8_t effectIndex)
 
void SpellEffectApplyAura (uint8_t effectIndex)
 
void SpellEffectEnvironmentalDamage (uint8_t effectIndex)
 
void SpellEffectPowerDrain (uint8_t effectIndex)
 
void SpellEffectHeal (uint8_t effectIndex)
 
void SpellEffectBind (uint8_t effectIndex)
 
void SpellEffectQuestComplete (uint8_t effectIndex)
 
void SpellEffectWeapondamageNoschool (uint8_t effectIndex)
 
void SpellEffectResurrect (uint8_t effectIndex)
 
void SpellEffectAddExtraAttacks (uint8_t effectIndex)
 
void SpellEffectDodge (uint8_t effectIndex)
 
void SpellEffectParry (uint8_t effectIndex)
 
void SpellEffectBlock (uint8_t effectIndex)
 
void SpellEffectCreateItem (uint8_t effectIndex)
 
void SpellEffectPersistentAA (uint8_t effectIndex)
 
virtual void SpellEffectSummon (uint8_t effectIndex)
 
void SpellEffectSummonWild (uint8_t effectIndex)
 
void SpellEffectSummonGuardian (uint32_t i, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties_, LocationVector &v)
 
void SpellEffectSummonTemporaryPet (uint32_t i, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties_, LocationVector &v)
 
void SpellEffectSummonPossessed (uint32_t i, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties_, LocationVector &v)
 
void SpellEffectSummonCompanion (uint32_t i, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties_, LocationVector &v)
 
void SpellEffectSummonVehicle (uint32_t i, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties_, LocationVector &v)
 
void SpellEffectLeap (uint8_t effectIndex)
 
void SpellEffectEnergize (uint8_t effectIndex)
 
void SpellEffectWeaponDmgPerc (uint8_t effectIndex)
 
void SpellEffectTriggerMissile (uint8_t effectIndex)
 
void SpellEffectOpenLock (uint8_t effectIndex)
 
void SpellEffectTransformItem (uint8_t effectIndex)
 
void SpellEffectApplyGroupAA (uint8_t effectIndex)
 
void SpellEffectLearnSpell (uint8_t effectIndex)
 
void SpellEffectSpellDefense (uint8_t effectIndex)
 
void SpellEffectDispel (uint8_t effectIndex)
 
void SpellEffectAddHonor (uint8_t effectIndex)
 
void SpellEffectSpawn (uint8_t effectIndex)
 
void SpellEffectSummonObject (uint8_t effectIndex)
 
void SpellEffectEnchantItem (uint8_t effectIndex)
 
void SpellEffectEnchantItemTemporary (uint8_t effectIndex)
 
void SpellEffectTameCreature (uint8_t effectIndex)
 
void SpellEffectSummonPet (uint8_t effectIndex)
 
void SpellEffectLearnPetSpell (uint8_t effectIndex)
 
void SpellEffectWeapondamage (uint8_t effectIndex)
 
void SpellEffectOpenLockItem (uint8_t effectIndex)
 
void SpellEffectSendEvent (uint8_t effectIndex)
 
void SpellEffectPowerBurn (uint8_t effectIndex)
 
void SpellEffectThreat (uint8_t effectIndex)
 
void SpellEffectClearQuest (uint8_t effectIndex)
 
void SpellEffectApplyRaidAA (uint8_t effectIndex)
 
void SpellEffectPowerFunnel (uint8_t effectIndex)
 
void SpellEffectHealMaxHealth (uint8_t effectIndex)
 
void SpellEffectInterruptCast (uint8_t effectIndex)
 
void SpellEffectDistract (uint8_t effectIndex)
 
void SpellEffectPickpocket (uint8_t effectIndex)
 
void SpellEffectAddFarsight (uint8_t effectIndex)
 
void SpellEffectUseGlyph (uint8_t effectIndex)
 
void SpellEffectHealMechanical (uint8_t effectIndex)
 
void SpellEffectSummonObjectWild (uint8_t effectIndex)
 
void SpellEffectSanctuary (uint8_t effectIndex)
 
void SpellEffectAddComboPoints (uint8_t effectIndex)
 
void SpellEffectCreateHouse (uint8_t effectIndex)
 
void SpellEffectDuel (uint8_t effectIndex)
 
void SpellEffectStuck (uint8_t effectIndex)
 
void SpellEffectSummonPlayer (uint8_t effectIndex)
 
void SpellEffectActivateObject (uint8_t effectIndex)
 
void SpellEffectBuildingDamage (uint8_t effectIndex)
 
void SpellEffectEnchantHeldItem (uint8_t effectIndex)
 
void SpellEffectForceDeselect (uint8_t effectIndex)
 
void SpellEffectSelfResurrect (uint8_t effectIndex)
 
void SpellEffectSkinning (uint8_t effectIndex)
 
void SpellEffectCharge (uint8_t effectIndex)
 
void SpellEffectKnockBack (uint8_t effectIndex)
 
void SpellEffectKnockBack2 (uint8_t effectIndex)
 
void SpellEffectPullTowardsDest (uint8_t effectIndex)
 
void SpellEffectDisenchant (uint8_t effectIndex)
 
void SpellEffectInebriate (uint8_t effectIndex)
 
void SpellEffectFeedPet (uint8_t effectIndex)
 
void SpellEffectDismissPet (uint8_t effectIndex)
 
void SpellEffectReputation (uint8_t effectIndex)
 
void SpellEffectSummonObjectSlot (uint8_t effectIndex)
 
void SpellEffectDispelMechanic (uint8_t effectIndex)
 
void SpellEffectSummonDeadPet (uint8_t effectIndex)
 
void SpellEffectDestroyAllTotems (uint8_t effectIndex)
 
void SpellEffectDurabilityDamage (uint8_t effectIndex)
 
void SpellEffectDurabilityDamagePCT (uint8_t effectIndex)
 
void SpellEffectResurrectNew (uint8_t effectIndex)
 
void SpellEffectAttackMe (uint8_t effectIndex)
 
void SpellEffectSkinPlayerCorpse (uint8_t effectIndex)
 
void SpellEffectApplyPetAA (uint8_t effectIndex)
 
void SpellEffectDummyMelee (uint8_t effectIndex)
 
void SpellEffectStartTaxi (uint8_t effectIndex)
 
void SpellEffectPlayerPull (uint8_t effectIndex)
 
void SpellEffectReduceThreatPercent (uint8_t effectIndex)
 
void SpellEffectSpellSteal (uint8_t effectIndex)
 
void SpellEffectProspecting (uint8_t effectIndex)
 
void SpellEffectApplyFriendAA (uint8_t effectIndex)
 
void SpellEffectApplyEnemyAA (uint8_t effectIndex)
 
void SpellEffectRedirectThreat (uint8_t effectIndex)
 
void SpellEffectPlayMusic (uint8_t effectIndex)
 
void SpellEffectForgetSpecialization (uint8_t effectIndex)
 
void SpellEffectKillCredit (uint8_t effectIndex)
 
void SpellEffectRestorePowerPct (uint8_t effectIndex)
 
void SpellEffectTriggerSpellWithValue (uint8_t effectIndex)
 
void SpellEffectApplyOwnerAA (uint8_t effectIndex)
 
void SpellEffectCreatePet (uint8_t effectIndex)
 
void SpellEffectTeachTaxiPath (uint8_t effectIndex)
 
void SpellEffectDualWield2H (uint8_t effectIndex)
 
void SpellEffectEnchantItemPrismatic (uint8_t effectIndex)
 
void SpellEffectCreateItem2 (uint8_t effectIndex)
 
void SpellEffectMilling (uint8_t effectIndex)
 
void SpellEffectRenamePet (uint8_t effectIndex)
 
void SpellEffectRestoreHealthPct (uint8_t effectIndex)
 
void SpellEffectLearnSpec (uint8_t effectIndex)
 
void SpellEffectActivateSpec (uint8_t effectIndex)
 
void SpellEffectActivateRunes (uint8_t effectIndex)
 
void SpellEffectJumpTarget (uint8_t effectIndex)
 
void SpellEffectJumpBehindTarget (uint8_t effectIndex)
 
uint32_t GetType ()
 
bool IsAspect ()
 
bool IsSeal ()
 
void InitProtoOverride ()
 
bool IsStealthSpell ()
 
bool IsInvisibilitySpell ()
 
bool DuelSpellNoMoreValid () const
 
bool GetSpellFailed () const
 
void SetSpellFailed (bool failed=true)
 
void SafeAddTarget (std::vector< uint64_t > *tgt, uint64_t guid)
 
void DetermineSkillUp (uint16_t skillid, uint32_t targetlevel, uint32_t multiplicator=1)
 
void DetermineSkillUp (uint16_t skillid)
 
bool AddTarget (uint32_t i, uint32_t TargetType, Object *obj)
 
void AddAOETargets (uint32_t i, uint32_t TargetType, float r, uint32_t maxtargets)
 
void AddPartyTargets (uint32_t i, uint32_t TargetType, float r, uint32_t maxtargets)
 
void AddRaidTargets (uint32_t i, uint32_t TargetType, float r, uint32_t maxtargets, bool partylimit=false)
 
void AddChainTargets (uint32_t i, uint32_t TargetType, float r, uint32_t maxtargets)
 
void AddConeTargets (uint32_t i, uint32_t TargetType, float r, uint32_t maxtargets)
 
void AddScriptedOrSpellFocusTargets (uint32_t i, uint32_t TargetType, float r, uint32_t maxtargets)
 

Static Public Member Functions

static uint32_t GetBaseThreat (uint32_t dmg)
 
static uint32_t GetMechanic (SpellInfo const *sp)
 

Public Attributes

std::shared_ptr< SpellForcedBasePointsforced_basepoints
 
uint32_t pSpellId
 
SpellInfo constProcedOnSpell
 
SpellCastTargets m_targets
 
uint32_t chaindamage
 
int32_t damage
 
bool m_AreaAura
 
int32_t m_charges
 
int32_t damageToHit
 
uint32_t castedItemId
 
uint8_t extra_cast_number
 
uint32_t m_glyphslot
 
float m_missilePitch
 
uint32_t m_missileTravelTime
 

Protected Member Functions

virtual int32_t DoCalculateEffect (uint32_t i, Unit *target, int32_t value)
 
virtual void DoAfterHandleEffect (Unit *target, uint32_t i)
 

Protected Attributes

float_t m_castPositionX = 0.0f
 
float_t m_castPositionY = 0.0f
 
float_t m_castPositionZ = 0.0f
 
float_t m_castPositionO = 0.0f
 
bool duelSpell = false
 
Objectm_caster = nullptr
 
Unitu_caster = nullptr
 
Playerp_caster = nullptr
 
GameObjectg_caster = nullptr
 
Itemi_caster = nullptr
 
Creaturem_targetConstraintCreature = nullptr
 
GameObjectm_targetConstraintGameObject = nullptr
 
SpellTargetConstraint constm_targetConstraint
 
bool m_Spell_Failed
 Spell state's.
 
bool m_Delayed
 
uint8_t m_DelayStep
 
bool m_IsCastedOnSelf
 
uint64_t m_magnetTarget
 
uint32_t add_damage
 
uint8_t m_rune_avail_before
 

Private Member Functions

SpellCastResult checkItems (uint32_t *parameter1, uint32_t *parameter2) const
 
SpellCastResult checkCasterState () const
 
SpellCastResult checkRange (const bool secondCheck)
 
SpellCastResult checkRunes (bool takeRunes)
 
SpellCastResult checkShapeshift (SpellInfo const *spellInfo, const uint32_t shapeshiftForm) const
 
void sendSpellStart ()
 
void sendSpellGo ()
 
void sendChannelStart (const uint32_t duration)
 
void sendCastResult (Player *caster, uint8_t castCount, SpellCastResult result, uint32_t parameter1, uint32_t parameter2)
 
void writeProjectileDataToPacket (WorldPacket *data)
 
void writeSpellMissedTargets (WorldPacket *data)
 
void takePower ()
 
uint32_t calculatePowerCost ()
 
SpellCastResult checkExplicitTarget (Object *target, uint32_t requiredTargetMask) const
 
void safeAddMissedTarget (uint64_t targetGuid, SpellDidHitResult hitResult, SpellDidHitResult extendedHitResult)
 
bool canAttackCreatureType (Creature *target) const
 
void removeCastItem ()
 
void removeReagents ()
 
void _updateCasterPointers (Object *caster)
 
void _updateTargetPointers (const uint64_t targetGuid)
 
void _loadInitialTargetPointers (bool reset=false)
 
float_t _getSpellTravelTimeForTarget (uint64_t guid) const
 
void _prepareProcFlags ()
 

Private Attributes

int32_t m_castTime = 0
 
int32_t m_timer = 0
 
uint32_t m_powerCost = 0
 
bool m_usesMana = false
 
std::vector< SpellUniqueTargetm_uniqueHittedTargets
 
std::vector< SpellTargetModm_missedTargets
 
std::vector< uint64_tm_effectTargets [MAX_SPELL_EFFECTS]
 
Unitm_unitTarget = nullptr
 
Itemm_itemTarget = nullptr
 
GameObjectm_gameObjTarget = nullptr
 
Playerm_playerTarget = nullptr
 
Corpsem_corpseTarget = nullptr
 
SpellInfo constm_spellInfo = nullptr
 
SpellInfo constm_spellInfo_override = nullptr
 
bool m_canBeReflected = false
 
bool m_requiresCP = false
 
int8_t m_usedComboPoints = 0
 
int32_t m_duration = 0
 
bool isDurationSet = false
 
float_t m_effectRadius [MAX_SPELL_EFFECTS] = { 0.0f }
 
bool m_isEffectRadiusSet [MAX_SPELL_EFFECTS] = { false }
 
DamageInfo m_casterDamageInfo = DamageInfo()
 
DamageInfo m_targetDamageInfo = DamageInfo()
 
bool isTargetDamageInfoSet = false
 
uint32_t m_casterProcFlags = 0
 
uint32_t m_targetProcFlags = 0
 
std::set< uint64_tm_doneTargetProcs
 
std::map< uint64_t, HitAuraEffectm_pendingAuras
 
std::map< uint64_t, HitSpellEffectm_hitEffects
 
std::map< uint64_t, MissSpellEffectm_missEffects
 
std::vector< uint64_tm_critTargets
 
bool isForcedCrit = false
 
bool isEffectDamageStatic [MAX_SPELL_EFFECTS]
 
float_t effectPctModifier [MAX_SPELL_EFFECTS]
 
std::map< AuraEffectModifier const *, boolm_usedModifiers
 
SpellState m_spellState = SPELL_STATE_NULL
 
SpellCastResult cancastresult = SPELL_CAST_SUCCESS
 
bool m_triggeredSpell = false
 
Auram_triggeredByAura = nullptr
 

Friends

class DummySpellHandler
 
class DynamicObject
 

Detailed Description

Definition at line 52 of file Spell.hpp.

Constructor & Destructor Documentation

◆ Spell()

Spell::Spell ( Object _caster,
SpellInfo const _spellInfo,
bool  _triggered,
Aura _aura 
)

Definition at line 75 of file Spell.cpp.

76{
77 if (_caster == nullptr)
78 {
79 sLogger.failure("Spell::Spell cant initialize without caster!");
80 return;
81 }
82
83 if (_spellInfo == nullptr)
84 {
85 sLogger.failure("Spell::Spell cant initialize without valid spell info!");
86 return;
87 }
88
89 _caster->m_pendingSpells.insert(this);
90 chaindamage = 0;
91 damage = 0;
92
93 m_DelayStep = 0;
94
95 m_AreaAura = false;
96
97 damageToHit = 0;
98 castedItemId = 0;
99
100 m_Spell_Failed = false;
101
102 add_damage = 0;
103 m_Delayed = false;
104 pSpellId = 0;
105 ProcedOnSpell = nullptr;
107 m_glyphslot = 0;
108 m_charges = _spellInfo->getProcCharges();
109
110 // create rune avail snapshot
112 m_rune_avail_before = static_cast<DeathKnight*>(p_caster)->GetRuneFlags();
113 else
115
116 m_targetConstraint = sSpellMgr.getSpellTargetConstraintForSpell(_spellInfo->getId());
117
118 m_missilePitch = 0;
120 m_IsCastedOnSelf = false;
121 m_magnetTarget = 0;
122
123 m_spellInfo = _spellInfo;
124
125 // Get spell difficulty
126 if (_spellInfo->getSpellDifficultyID() != 0 && !_caster->isPlayer() && _caster->getWorldMap() != nullptr)
127 {
128 auto SpellDiffEntry = sSpellMgr.getSpellInfoByDifficulty(_spellInfo->getSpellDifficultyID(), _caster->getWorldMap()->getDifficulty());
129 if (SpellDiffEntry != nullptr)
130 m_spellInfo = SpellDiffEntry;
131 }
132
133 // Initialize caster pointers
134 _updateCasterPointers(_caster);
135
136 // Check if spell is casted in a duel
137 switch (_caster->getObjectTypeId())
138 {
139 case TYPEID_PLAYER:
140 case TYPEID_UNIT:
142 duelSpell = true;
143 break;
144 case TYPEID_ITEM:
145 case TYPEID_CONTAINER:
147 duelSpell = true;
148 break;
151 duelSpell = true;
152 break;
153 default:
154 break;
155 }
156
157 if (u_caster && getSpellInfo()->getAttributesExF() & ATTRIBUTESEXF_CAST_BY_CHARMER)
158 {
159 const auto unitCharmer = u_caster->getWorldMapUnit(u_caster->getCharmedByGuid());
160 if (unitCharmer != nullptr)
161 {
162 u_caster = unitCharmer;
163 if (unitCharmer->isPlayer())
164 p_caster = dynamic_cast<Player*>(unitCharmer);
165 }
166 }
167
168 m_triggeredSpell = _triggered;
169 m_triggeredByAura = _aura;
171 m_triggeredSpell = true;
172
174
175 m_uniqueHittedTargets.clear();
176 m_missedTargets.clear();
177
178 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
179 {
180 isEffectDamageStatic[i] = false;
181 effectPctModifier[i] = 1.0f;
182
183 m_effectTargets[i].clear();
184 }
185
186 // Check if spell is reflectable
190 {
191 //\ todo: this is not correct but it works for now
192 //\ need to check for effect rather than target type
193 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
194 {
196 {
200 case EFF_TARGET_DUEL:
201 m_canBeReflected = true;
202 break;
203 default:
204 break;
205 }
206
208 break;
209 }
210 }
211
212 forced_basepoints = std::make_shared<SpellForcedBasePoints>();
213}
#define sLogger
Definition Logger.hpp:136
@ TYPEID_GAMEOBJECT
@ TYPEID_UNIT
@ TYPEID_ITEM
@ TYPEID_PLAYER
@ TYPEID_CONTAINER
@ DUEL_STATE_STARTED
@ SPELL_DMG_TYPE_MAGIC
@ ATTRIBUTESEXD_TRIGGERED
@ ATTRIBUTESEXF_CAST_BY_CHARMER
@ ATTRIBUTESEX_REQ_COMBO_POINTS1
@ ATTRIBUTESEX_CANT_BE_REFLECTED
@ ATTRIBUTESEX_REQ_COMBO_POINTS2
@ ATTRIBUTES_IGNORE_INVULNERABILITY
@ ATTRIBUTES_ABILITY
@ EFF_TARGET_SINGLE_ENEMY
@ EFF_TARGET_DUEL
@ EFF_TARGET_IN_FRONT_OF_CASTER
@ EFF_TARGET_ALL_ENEMIES_AROUND_CASTER
#define sSpellMgr
Definition SpellMgr.hpp:197
static constexpr uint8_t MAX_SPELL_EFFECTS
Player * getPlayerOwner() override
Player * getOwner() const
Definition Item.cpp:945
Unit * getWorldMapUnit(const uint64_t &guid) const
Definition Object.cpp:4578
virtual Player * getPlayerOwnerOrSelf()
Definition Object.cpp:1753
std::set< Spell * > m_pendingSpells
Definition Object.hpp:767
WorldMap * getWorldMap() const
Definition Object.hpp:454
uint8_t getObjectTypeId() const
Definition Object.cpp:566
bool isPlayer() const
Definition Object.cpp:569
uint8_t getDuelState() const
Definition Player.cpp:12129
virtual bool isClassDeathKnight() const
Definition Player.cpp:2763
bool isPassive() const
uint32_t getDmgClass() const
uint32_t getAttributes() const
uint32_t getAttributesExD() const
uint32_t getProcCharges() const
uint32_t getAttributesEx() const
uint32_t getEffectImplicitTargetA(uint8_t idx) const
SpellInfo const * ProcedOnSpell
Definition Spell.hpp:534
uint32_t castedItemId
Definition Spell.hpp:684
bool isEffectDamageStatic[MAX_SPELL_EFFECTS]
Definition Spell.hpp:331
std::vector< SpellUniqueTarget > m_uniqueHittedTargets
Definition Spell.hpp:195
SpellTargetConstraint const * m_targetConstraint
Definition Spell.hpp:215
Player * p_caster
Definition Spell.hpp:164
bool duelSpell
Definition Spell.hpp:160
uint8_t m_DelayStep
Definition Spell.hpp:706
SpellInfo const * getSpellInfo() const
Definition Spell.cpp:5789
bool m_triggeredSpell
Definition Spell.hpp:339
bool m_AreaAura
Definition Spell.hpp:680
Unit * u_caster
Definition Spell.hpp:163
GameObject * g_caster
Definition Spell.hpp:165
bool m_Delayed
Definition Spell.hpp:705
uint8_t m_rune_avail_before
Definition Spell.hpp:714
std::shared_ptr< SpellForcedBasePoints > forced_basepoints
Definition Spell.hpp:245
SpellInfo const * m_spellInfo
Definition Spell.hpp:236
uint8_t extra_cast_number
Definition Spell.hpp:685
bool m_IsCastedOnSelf
Definition Spell.hpp:708
uint32_t pSpellId
Definition Spell.hpp:533
bool m_requiresCP
Definition Spell.hpp:302
uint32_t add_damage
Definition Spell.hpp:712
uint64_t m_magnetTarget
Definition Spell.hpp:710
float_t effectPctModifier[MAX_SPELL_EFFECTS]
Definition Spell.hpp:332
Item * i_caster
Definition Spell.hpp:166
bool m_Spell_Failed
Spell state's.
Definition Spell.hpp:704
uint32_t m_missileTravelTime
Definition Spell.hpp:722
int32_t m_charges
Definition Spell.hpp:681
std::vector< SpellTargetMod > m_missedTargets
Definition Spell.hpp:197
std::vector< uint64_t > m_effectTargets[MAX_SPELL_EFFECTS]
Definition Spell.hpp:199
uint32_t chaindamage
Definition Spell.hpp:665
uint32_t m_glyphslot
Definition Spell.hpp:686
int32_t damage
Definition Spell.hpp:679
void _updateCasterPointers(Object *caster)
Definition Spell.cpp:6129
Aura * m_triggeredByAura
Definition Spell.hpp:340
int32_t damageToHit
Definition Spell.hpp:683
float m_missilePitch
Definition Spell.hpp:721
bool m_canBeReflected
Definition Spell.hpp:300
uint64_t getCharmedByGuid() const
Definition Unit.cpp:391
InstanceDifficulty::Difficulties getDifficulty() const
Definition WorldMap.hpp:216
unsigned char uint8_t
Here is the call graph for this function:

◆ ~Spell()

Spell::~Spell ( )

Definition at line 215 of file Spell.cpp.

216{
217#if VERSION_STRING >= WotLK
218 // If this spell deals with rune power, send spell_go to update client
219 // For instance, when Dk cast Empower Rune Weapon, if we don't send spell_go, the client won't update
220 if (getSpellInfo()->getFirstSchoolFromSchoolMask() && getSpellInfo()->getPowerType() == POWER_TYPE_RUNES)
221 sendSpellGo();
222#endif
223
224 m_caster->m_pendingSpells.erase(this);
225
226 ///////////////////////////// This is from the virtual_destructor shit ///////////////
227 for (uint8_t i = 0; i < CURRENT_SPELL_MAX; ++i)
228 {
231 }
232
234 delete[] m_spellInfo_override;
235 ////////////////////////////////////////////////////////////////////////////////////////
236
237
238 for (auto& effectTarget : m_effectTargets)
239 effectTarget.clear();
240
241 m_uniqueHittedTargets.clear();
242 m_missedTargets.clear();
243
244 m_hitEffects.clear();
245 m_missEffects.clear();
246 m_critTargets.clear();
247
248 m_usedModifiers.clear();
249 m_pendingAuras.clear();
250}
CurrentSpellType
Definition Object.hpp:65
@ CURRENT_SPELL_MAX
Definition Object.hpp:70
@ POWER_TYPE_RUNES
Definition PowerType.hpp:23
void interruptSpellWithSpellType(CurrentSpellType spellType)
Definition Object.cpp:713
Spell * getCurrentSpell(CurrentSpellType spellType) const
Definition Object.cpp:600
Object * m_caster
Definition Spell.hpp:162
void sendSpellGo()
Definition Spell.cpp:4942
SpellInfo const * m_spellInfo_override
Definition Spell.hpp:239
std::map< uint64_t, MissSpellEffect > m_missEffects
Definition Spell.hpp:327
std::map< uint64_t, HitSpellEffect > m_hitEffects
Definition Spell.hpp:326
std::vector< uint64_t > m_critTargets
Definition Spell.hpp:328
std::map< uint64_t, HitAuraEffect > m_pendingAuras
Definition Spell.hpp:325
std::map< AuraEffectModifier const *, bool > m_usedModifiers
Definition Spell.hpp:334
Here is the call graph for this function:

Member Function Documentation

◆ _getSpellTravelTimeForTarget()

float_t Spell::_getSpellTravelTimeForTarget ( uint64_t  guid) const
private

Definition at line 6267 of file Spell.cpp.

6268{
6269 // Handle instant spells instantly
6270 if (getSpellInfo()->getSpeed() == 0)
6271 return 0.0f;
6272
6273 float_t destX = 0.0f, destY = 0.0f, destZ = 0.0f, distance = 0.0f;
6274
6275 // Use destination only if the spell has no unit target mask set
6277 {
6278 const auto dest = m_targets.getDestination();
6279 destX = dest.x;
6280 destY = dest.y;
6281 destZ = dest.z;
6282
6283 distance = m_caster->CalcDistance(destX, destY, destZ);
6284 }
6285 else if (guid == 0)
6286 {
6287 return -1.0f;
6288 }
6289 else
6290 {
6291 if (!m_caster->IsInWorld())
6292 return -1.0f;
6293
6294 if (m_caster->getGuid() != guid)
6295 {
6296 const auto obj = m_caster->getWorldMapObject(guid);
6297 if (obj == nullptr)
6298 return -1.0f;
6299
6300 destX = obj->GetPositionX();
6301 destY = obj->GetPositionY();
6302 //\todo this should be destz = obj->GetPositionZ() + (obj->GetModelHighBoundZ() / 2 * obj->getScale())
6303 if (obj->isCreatureOrPlayer())
6304 destZ = obj->GetPositionZ() + static_cast<Unit*>(obj)->getModelHalfSize();
6305 else
6306 destZ = obj->GetPositionZ();
6307
6308 distance = m_caster->CalcDistance(destX, destY, destZ);
6309 }
6310 }
6311
6312 if (distance == 0.0f)
6313 return 0.0f;
6314
6315 if (m_missileTravelTime != 0)
6316 return static_cast<float_t>(m_missileTravelTime);
6317
6318 // Calculate time it takes for spell to hit target
6319 return distance * 1000.0f / getSpellInfo()->getSpeed();
6320}
@ TARGET_FLAG_UNIT
uint64_t getGuid() const
Definition Object.cpp:295
Object * getWorldMapObject(const uint64_t &guid) const
Definition Object.cpp:4559
float CalcDistance(Object *Ob)
Definition Object.cpp:3555
bool IsInWorld() const
Definition Object.hpp:98
const float & GetPositionX() const
Definition Object.hpp:354
const float & GetPositionZ() const
Definition Object.hpp:356
LocationVector getDestination() const
bool hasDestination() const
uint32_t getTargetMask() const
float getSpeed() const
SpellCastTargets m_targets
Definition Spell.hpp:535
Definition Unit.hpp:147
double distance(double x, double y)
Definition g3dmath.h:731
Here is the call graph for this function:
Here is the caller graph for this function:

◆ _loadInitialTargetPointers()

void Spell::_loadInitialTargetPointers ( bool  reset = false)
private

Definition at line 6234 of file Spell.cpp.

6235{
6237
6238 if (reset)
6239 return;
6240
6243
6244 if (m_targets.getItemTargetGuid() != 0 && getPlayerCaster() != nullptr)
6245 {
6246 if (m_targets.isTradeItem())
6247 {
6248 const auto* const playerTrader = getPlayerCaster()->getTradeTarget();
6249 if (playerTrader != nullptr)
6250 m_itemTarget = playerTrader->getTradeData()->getTradeItem(TradeSlots(m_targets.getItemTargetGuid()));
6251 }
6252 else
6253 {
6255 }
6256 }
6257
6258 if (m_targets.getUnitTargetGuid() != 0)
6259 {
6261
6262 if (m_unitTarget != nullptr && m_unitTarget->isPlayer())
6263 m_playerTarget = dynamic_cast<Player*>(m_unitTarget);
6264 }
6265}
TradeSlots
Item * GetItemByGUID(uint64_t itemGuid)
Gets a Item by guid.
GameObject * getWorldMapGameObject(const uint64_t &guid) const
Definition Object.cpp:4608
ItemInterface * getItemInterface() const
Definition Player.cpp:6934
Player * getTradeTarget() const
Definition Player.cpp:6501
uint64_t getItemTargetGuid() const
uint64_t getUnitTargetGuid() const
uint64_t getGameObjectTargetGuid() const
void unsetAllTargets()
Definition Spell.cpp:5690
Unit * m_unitTarget
Definition Spell.hpp:204
GameObject * m_gameObjTarget
Definition Spell.hpp:206
Player * getPlayerCaster() const
Definition Spell.cpp:5639
Item * m_itemTarget
Definition Spell.hpp:205
Player * m_playerTarget
Definition Spell.hpp:207
Here is the call graph for this function:
Here is the caller graph for this function:

◆ _prepareProcFlags()

void Spell::_prepareProcFlags ( )
private

Definition at line 6322 of file Spell.cpp.

6323{
6324 // Setup spell target mask
6325 uint32_t spellTargetMask = 0;
6326 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
6327 {
6328 if (getSpellInfo()->getEffect(i) == 0)
6329 continue;
6330
6331 // Skip targets on following effects
6332 // Procs for these effects are handled when the real spell is casted
6333 if (getSpellInfo()->getEffect(i) == SPELL_EFFECT_DUMMY ||
6334 getSpellInfo()->getEffect(i) == SPELL_EFFECT_SCRIPT_EFFECT ||
6335 getSpellInfo()->getEffect(i) == SPELL_EFFECT_TRIGGER_SPELL
6336#if VERSION_STRING >= TBC
6338#endif
6339 )
6340 continue;
6341
6342 spellTargetMask |= getSpellInfo()->getRequiredTargetMaskForEffect(i);
6343 }
6344
6345 if (spellTargetMask == 0)
6346 return;
6347
6348 // Set initial proc flags here, correct flags are set in Object::doSpellDamage and ::doSpellHealing
6349 // Consider the spell negative if it requires an attackable target
6350 const auto spellDamageType = getSpellInfo()->getDmgClass();
6351 if (spellTargetMask & SPELL_TARGET_REQUIRE_ATTACKABLE)
6352 {
6353 if (spellDamageType == SPELL_DMG_TYPE_NONE)
6354 {
6357 }
6358 else if (spellDamageType == SPELL_DMG_TYPE_MAGIC)
6359 {
6362 }
6363 }
6364 else
6365 {
6366 if (spellDamageType == SPELL_DMG_TYPE_NONE)
6367 {
6370 }
6371 else if (spellDamageType == SPELL_DMG_TYPE_MAGIC)
6372 {
6375 }
6376 }
6377
6378 auto isCasterOnlyTarget = false;
6379 if (m_uniqueHittedTargets.size() == 1)
6380 isCasterOnlyTarget = m_caster->getGuid() == m_uniqueHittedTargets.front().first;
6381
6382 // These proc flags should not be applied if spell has no targets or is only targeting caster
6383 if (!(spellTargetMask & SPELL_TARGET_OBJECT_SELF) && m_uniqueHittedTargets.size() > 0 && !isCasterOnlyTarget)
6384 {
6385 // Set initial flags here, correct flags are set in Unit::Strike
6386 if (spellDamageType == SPELL_DMG_TYPE_MELEE)
6387 {
6390 }
6391 else if (spellDamageType == SPELL_DMG_TYPE_RANGED)
6392 {
6395 }
6396 }
6397}
@ PROC_ON_TAKEN_NEGATIVE_SPELL_DAMAGE_CLASS_MAGIC
Definition ProcFlags.hpp:34
@ PROC_ON_TAKEN_NEGATIVE_SPELL_DAMAGE_CLASS_NONE
Definition ProcFlags.hpp:29
@ PROC_ON_DONE_NEGATIVE_SPELL_DAMAGE_CLASS_MAGIC
Definition ProcFlags.hpp:33
@ PROC_ON_TAKEN_POSITIVE_SPELL_DAMAGE_CLASS_MAGIC
Definition ProcFlags.hpp:32
@ PROC_ON_DONE_POSITIVE_SPELL_DAMAGE_CLASS_NONE
Definition ProcFlags.hpp:26
@ PROC_ON_TAKEN_POSITIVE_SPELL_DAMAGE_CLASS_NONE
Definition ProcFlags.hpp:27
@ PROC_ON_TAKEN_RANGED_SPELL_HIT
Definition ProcFlags.hpp:24
@ PROC_ON_TAKEN_MELEE_SPELL_HIT
Definition ProcFlags.hpp:19
@ PROC_ON_DONE_MELEE_SPELL_HIT
Definition ProcFlags.hpp:18
@ PROC_ON_DONE_POSITIVE_SPELL_DAMAGE_CLASS_MAGIC
Definition ProcFlags.hpp:31
@ PROC_ON_DONE_NEGATIVE_SPELL_DAMAGE_CLASS_NONE
Definition ProcFlags.hpp:28
@ PROC_ON_DONE_RANGED_SPELL_HIT
Definition ProcFlags.hpp:23
@ SPELL_DMG_TYPE_NONE
@ SPELL_DMG_TYPE_MELEE
@ SPELL_DMG_TYPE_RANGED
@ SPELL_EFFECT_DUMMY
@ SPELL_EFFECT_SCRIPT_EFFECT
@ SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
@ SPELL_EFFECT_TRIGGER_SPELL
@ SPELL_TARGET_REQUIRE_ATTACKABLE
Definition SpellTarget.h:28
@ SPELL_TARGET_OBJECT_SELF
scripted units
Definition SpellTarget.h:31
uint32_t getRequiredTargetMaskForEffect(uint8_t effectIndex, bool getExplicitMask=false) const
uint32_t m_targetProcFlags
Definition Spell.hpp:316
uint32_t m_casterProcFlags
Definition Spell.hpp:315
unsigned int uint32_t
Here is the call graph for this function:
Here is the caller graph for this function:

◆ _updateCasterPointers()

void Spell::_updateCasterPointers ( Object caster)
private

Definition at line 6129 of file Spell.cpp.

6130{
6131 p_caster = nullptr;
6132 u_caster = nullptr;
6133 i_caster = nullptr;
6134 g_caster = nullptr;
6135
6136 m_caster = caster;
6137 switch (caster->getObjectTypeId())
6138 {
6139 case TYPEID_PLAYER:
6140 p_caster = dynamic_cast<Player*>(caster);
6141 [[fallthrough]];
6142 case TYPEID_UNIT:
6143 u_caster = dynamic_cast<Unit*>(caster);
6144 break;
6145 case TYPEID_ITEM:
6146 case TYPEID_CONTAINER:
6147 i_caster = dynamic_cast<Item*>(caster);
6148 break;
6149 case TYPEID_GAMEOBJECT:
6150 g_caster = dynamic_cast<GameObject*>(caster);
6151 break;
6152 default:
6153 sLogger.debugFlag(AscEmu::Logging::LF_SPELL, "Spell::_updateCasterPointers : Incompatible object type (type {}) for spell caster", caster->getObjectTypeId());
6154 break;
6155 }
6156}
Definition Item.hpp:43
Here is the call graph for this function:
Here is the caller graph for this function:

◆ _updateTargetPointers()

void Spell::_updateTargetPointers ( const uint64_t  targetGuid)
private

Definition at line 6158 of file Spell.cpp.

6159{
6161
6162 if (targetGuid == 0)
6163 {
6164 if (getPlayerCaster() != nullptr)
6165 {
6168
6169 if (m_targets.isTradeItem())
6170 {
6171 const auto trader = getPlayerCaster()->getTradeTarget();
6172 if (trader != nullptr)
6173 m_itemTarget = trader->getTradeData()->getTradeItem(TradeSlots(m_targets.getItemTargetGuid()));
6174 }
6175 }
6176 }
6177 else if (targetGuid == getCaster()->getGuid())
6178 {
6183 }
6184 else
6185 {
6186 if (!getCaster()->IsInWorld())
6187 return;
6188
6189 if (m_targets.isTradeItem())
6190 {
6191 if (getPlayerCaster() != nullptr)
6192 {
6193 const auto trader = getPlayerCaster()->getTradeTarget();
6194 if (trader != nullptr)
6195 m_itemTarget = trader->getTradeData()->getTradeItem(TradeSlots(targetGuid));
6196 }
6197 }
6198 else
6199 {
6200 WoWGuid wowGuid;
6201 wowGuid.Init(targetGuid);
6202
6203 switch (wowGuid.getHigh())
6204 {
6205 case HighGuid::Unit:
6206 case HighGuid::Vehicle:
6208 break;
6209 case HighGuid::Pet:
6211 break;
6212 case HighGuid::Player:
6214 m_playerTarget = dynamic_cast<Player*>(m_unitTarget);
6215 break;
6216 case HighGuid::Item:
6217 if (getPlayerCaster() != nullptr)
6219 break;
6222 break;
6223 case HighGuid::Corpse:
6224 m_corpseTarget = sObjectMgr.getCorpseByGuid(wowGuid.getGuidLowPart());
6225 break;
6226 default:
6227 sLogger.failure("Spell::_updateTargetPointers : Invalid object type for spell target (low guid {}) in spell {}", wowGuid.getGuidLowPart(), getSpellInfo()->getId());
6228 break;
6229 }
6230 }
6231 }
6232}
#define sObjectMgr
@ TARGET_FLAG_ITEM
Unit * getUnitCaster() const
Definition Spell.cpp:5634
Object * getCaster() const
Definition Spell.cpp:5629
Item * getItemCaster() const
Definition Spell.cpp:5649
Corpse * m_corpseTarget
Definition Spell.hpp:208
GameObject * getGameObjectCaster() const
Definition Spell.cpp:5644
HighGuid getHigh() const
Definition WoWGuid.h:247
uint32_t getGuidLowPart() const
Definition WoWGuid.h:222
void Init(uint64_t guid)
Definition WoWGuid.h:176
GameObject * getGameObject(uint32_t guid)
Pet * getPet(uint32_t guid)
Creature * getCreature(uint32_t guid)
Player * getPlayer(uint32_t guid)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AddAOETargets()

void Spell::AddAOETargets ( uint32_t  i,
uint32_t  TargetType,
float  r,
uint32_t  maxtargets 
)

Definition at line 305 of file SpellTarget.Legacy.cpp.

306{
307 LocationVector source;
308
309 //cant do raid/party stuff here, seperate functions for it
310 if (targetType & (SPELL_TARGET_AREA_PARTY | SPELL_TARGET_AREA_RAID) && !(p_caster == nullptr && !m_caster->isPet() && (!m_caster->isCreature() || !m_caster->isTotem())))
311 return;
312
314
315 if (targetType & SPELL_TARGET_AREA_SELF)
316 source = m_caster->GetPosition();
317 else if (targetType & SPELL_TARGET_AREA_CURTARGET && tarobj != nullptr)
318 source = tarobj->GetPosition();
319 else
320 {
322 {
323 // If position is not set, try unit target's position
324 if (m_targets.getUnitTargetGuid() != 0)
325 {
326 const auto targetUnit = m_caster->getWorldMapUnit(m_targets.getUnitTargetGuid());
327 if (targetUnit != nullptr)
328 m_targets.setDestination(targetUnit->GetPosition());
329 }
330
331 // Check again if position was set
333 {
334 // No unit target => use caster's position
336 }
337 }
338
339 source = m_targets.getDestination();
340 }
341
342 //caster might be in the aoe LOL
343 if (!(targetType & SPELL_TARGET_REQUIRE_ATTACKABLE))
344 {
345 if (m_caster->CalcDistance(source) <= r)
346 AddTarget(i, targetType, m_caster);
347 }
348
349 std::vector<uint64_t>* t = &m_effectTargets[i];
350
351 for (const auto& itr : m_caster->getInRangeObjectsSet())
352 {
353 if (!itr)
354 continue;
355
356 if (maxtargets != 0 && t->size() >= maxtargets)
357 break;
358
359 float dist = itr->CalcDistance(source);
360 if (dist <= r)
361 AddTarget(i, targetType, itr);
362 }
363}
@ SPELL_TARGET_AREA_SELF
Definition SpellTarget.h:38
@ SPELL_TARGET_AREA_RAID
Definition SpellTarget.h:44
@ SPELL_TARGET_AREA_CURTARGET
Definition SpellTarget.h:41
@ SPELL_TARGET_AREA_PARTY
Definition SpellTarget.h:43
bool isSet() const
LocationVector GetPosition() const
Definition Object.hpp:373
virtual bool isTotem() const
Definition Object.hpp:204
virtual bool isPet() const
Definition Object.hpp:203
bool isCreature() const
Definition Object.cpp:570
void setDestination(LocationVector destination)
bool AddTarget(uint32_t i, uint32_t TargetType, Object *obj)
Object * getObject(const uint64_t &guid)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AddChainTargets()

void Spell::AddChainTargets ( uint32_t  i,
uint32_t  TargetType,
float  r,
uint32_t  maxtargets 
)

Definition at line 161 of file SpellTarget.Legacy.cpp.

162{
163 if (!m_caster->IsInWorld())
164 return;
165
167
168 if (targ == nullptr)
169 return;
170
171 std::vector<uint64_t>* list = &m_effectTargets[i];
172
173 //if selected target is party member, then jumps on party
174 Unit* firstTarget = nullptr;
175
176 if (targ->isCreatureOrPlayer())
177 firstTarget = static_cast<Unit*>(targ);
178 else
179 firstTarget = u_caster;
180
181 bool RaidOnly = false;
182 float range = m_spellInfo->getMaxRange(false, m_caster, this);//this is probably wrong,
183 //this is cast distance, not searching distance
184 range *= range;
185
186 //is this party only?
187 Player* casterFrom = u_caster->getPlayerOwnerOrSelf();
188 Player* pfirstTargetFrom = firstTarget->getPlayerOwnerOrSelf();
189 if (casterFrom != nullptr && pfirstTargetFrom != nullptr && casterFrom->getGroup() == pfirstTargetFrom->getGroup())
190 RaidOnly = true;
191
192 uint32_t jumps = m_spellInfo->getEffectChainTarget(static_cast<uint8_t>(i));
193
194 //range
195 range /= jumps; //hacky, needs better implementation!
196
198
199 AddTarget(i, targetType, firstTarget);
200
201 if (jumps <= 1 || list->size() == 0) //1 because we've added the first target, 0 size if spell is resisted
202 return;
203
204 for (const auto& itr : firstTarget->getInRangeObjectsSet())
205 {
206 auto obj = itr;
207 if (!obj || !itr->isCreatureOrPlayer() || !static_cast<Unit*>(itr)->isAlive())
208 continue;
209
210 if (RaidOnly && !pfirstTargetFrom->isUnitOwnerInRaid(static_cast<Unit*>(itr)))
211 continue;
212
213 //healing spell, full health target = NONO
214 if (m_spellInfo->isHealingSpell() && static_cast<Unit*>(itr)->getHealthPct() == 100)
215 continue;
216
217 if (obj->isInRange(firstTarget->GetPositionX(), firstTarget->GetPositionY(), firstTarget->GetPositionZ(), range))
218 {
219 size_t oldsize = list->size();
220 AddTarget(i, targetType, itr);
221 if (list->size() == oldsize || list->size() >= jumps) //either out of jumps or a resist
222 return;
223 }
224 }
225}
@ SPELLMOD_ADDITIONAL_TARGET
bool isCreatureOrPlayer() const
Definition Object.cpp:568
const float & GetPositionY() const
Definition Object.hpp:355
Group * getGroup()
Definition Player.cpp:7887
bool isHealingSpell() const
float_t getMaxRange(bool friendly=false, Object *caster=nullptr, Spell *spell=nullptr) const
uint32_t getEffectChainTarget(uint8_t idx) const
void applySpellModifiers(SpellModifierType modType, T *value, SpellInfo const *spellInfo, Spell *castingSpell=nullptr, Aura *castingAura=nullptr)
Definition Unit.cpp:4465
bool isUnitOwnerInRaid(Unit *unit)
Definition Unit.cpp:7977
uint8_t getHealthPct() const
Definition Unit.cpp:6704
bool isAlive() const
Definition Unit.cpp:7871
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AddConeTargets()

void Spell::AddConeTargets ( uint32_t  i,
uint32_t  TargetType,
float  r,
uint32_t  maxtargets 
)

Definition at line 140 of file SpellTarget.Legacy.cpp.

141{
142 std::vector<uint64_t>* list = &m_effectTargets[i];
143 for (const auto& itr : m_caster->getInRangeObjectsSet())
144 {
145 if (!itr || !itr->isCreatureOrPlayer() || !static_cast<Unit*>(itr)->isAlive())
146 continue;
147
148 //is Creature in range
149 if (m_caster->isInRange(itr, getEffectRadius(i)))
150 {
151 if (m_spellInfo->cone_width ? m_caster->isInArc(itr, m_spellInfo->cone_width) : m_caster->isInFront(itr)) // !!! is the target within our cone ?
152 {
153 AddTarget(i, targetType, itr);
154 }
155 }
156 if (maxtargets != 0 && list->size() >= maxtargets)
157 return;
158 }
159}
bool isInArc(Object *target, float degrees)
Definition Object.cpp:3827
bool isInRange(LocationVector location, float square_r) const
Definition Object.cpp:578
float cone_width
float_t getEffectRadius(uint8_t effectIndex)
Definition Spell.cpp:5969
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AddPartyTargets()

void Spell::AddPartyTargets ( uint32_t  i,
uint32_t  TargetType,
float  r,
uint32_t  maxtargets 
)

Definition at line 227 of file SpellTarget.Legacy.cpp.

228{
230 if (u == nullptr)
231 u = m_caster;
232
233 // If spell has area aura effect, aura code will handle proper targetting
234 // so add just caster
235 if (getSpellInfo()->isAreaAuraEffect(i))
236 {
237 AddTarget(i, targetType, u);
238 return;
239 }
240
242 if (p == nullptr || u_caster == nullptr)
243 return;
244
245 AddTarget(i, targetType, p);
246
247 for (const auto& itr : u->getInRangeObjectsSet())
248 {
249 if (!itr || !itr->isCreatureOrPlayer() || !static_cast<Unit*>(itr)->isAlive())
250 continue;
251
252 //only affect players and pets
253 if (!itr->isPlayer() && !itr->isPet())
254 continue;
255
256 if (!p->isUnitOwnerInParty(static_cast<Unit*>(itr)))
257 continue;
258
259 if (u->CalcDistance(itr) > r)
260 continue;
261
262 AddTarget(i, targetType, itr);
263 }
264}
bool isUnitOwnerInParty(Unit *unit)
Definition Unit.cpp:7955
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AddRaidTargets()

void Spell::AddRaidTargets ( uint32_t  i,
uint32_t  TargetType,
float  r,
uint32_t  maxtargets,
bool  partylimit = false 
)

Definition at line 266 of file SpellTarget.Legacy.cpp.

267{
269 if (u == nullptr)
270 u = m_caster;
271
272 // If spell has area aura effect, aura code will handle proper targetting
273 // so add just caster
274 if (getSpellInfo()->isAreaAuraEffect(i))
275 {
276 AddTarget(i, targetType, u);
277 return;
278 }
279
281 if (p == nullptr || u_caster == nullptr)
282 return;
283
284 AddTarget(i, targetType, p);
285
286 for (const auto& itr : u->getInRangeObjectsSet())
287 {
288 if (!itr || !itr->isCreatureOrPlayer() || !static_cast<Unit*>(itr)->isAlive())
289 continue;
290
291 //only affect players and pets
292 if (!itr->isPlayer() && !itr->isPet())
293 continue;
294
295 if (!p->isUnitOwnerInRaid(static_cast<Unit*>(itr)))
296 continue;
297
298 if (u->CalcDistance(itr) > r)
299 continue;
300
301 AddTarget(i, targetType, itr);
302 }
303}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AddScriptedOrSpellFocusTargets()

void Spell::AddScriptedOrSpellFocusTargets ( uint32_t  i,
uint32_t  TargetType,
float  r,
uint32_t  maxtargets 
)

Definition at line 118 of file SpellTarget.Legacy.cpp.

119{
120 for (const auto& itr : m_caster->getInRangeObjectsSet())
121 {
122 Object* o = itr;
123 if (!o || !o->isGameObject())
124 continue;
125
126 GameObject* go = static_cast<GameObject*>(o);
128 {
129 if (!m_caster->isInRange(go, r))
130 continue;
131
132 bool success = AddTarget(i, targetType, go);
133
134 if (success)
135 return;
136 }
137 }
138}
GameObjectProperties const * GetGameObjectProperties() const
bool isGameObject() const
Definition Object.cpp:572
uint32_t getRequiresSpellFocus() const
struct GameObjectProperties::@162::@185 raw
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AddTarget()

bool Spell::AddTarget ( uint32_t  i,
uint32_t  TargetType,
Object obj 
)
Todo:
Add support for this in arcemu

Definition at line 365 of file SpellTarget.Legacy.cpp.

366{
367 const auto targetCheck = checkExplicitTarget(obj, TargetType);
368 if (targetCheck != SPELL_CAST_SUCCESS)
369 return false;
370
371 // If checked in checkExplicitTarget, initial aoe spell cast check can fail
372 if (getSpellInfo()->getAttributesExC() & ATTRIBUTESEXC_TARGET_ONLY_PLAYERS && !obj->isPlayer())
373 return false;
374
375 if (u_caster != nullptr && u_caster->hasUnitFlags(UNIT_FLAG_IGNORE_PLAYER_COMBAT) && ((obj->isPlayer() || obj->isPet()) || (p_caster != nullptr || m_caster->isPet())))
376 return false;
377
378 std::vector<uint64_t>* t = &m_effectTargets[i];
379
381 if (hitresult != SPELL_DID_HIT_SUCCESS)
382 {
384 if (hitresult == SPELL_DID_HIT_REFLECT && u_caster != nullptr)
385 {
386 //for checks
387 Unit* tmp = u_caster;
388 u_caster = static_cast<Unit*>(obj);
389 extended = static_cast<SpellDidHitResult>(DidHit(i, tmp));
390 u_caster = tmp;
391 }
392 safeAddMissedTarget(obj->getGuid(), hitresult, extended);
393 return false;
394 }
395 else
396 {
397 //check target isnt already in
398 for (std::vector<uint64_t>::iterator itr = m_effectTargets[i].begin(); itr != m_effectTargets[i].end(); ++itr)
399 {
400 if (obj->getGuid() == *itr)
401 return false;
402 }
403 t->push_back(obj->getGuid());
404 }
405
406 //final checks, require line of sight unless range/radius is 50000 yards
407 auto spell_range = sSpellRangeStore.lookupEntry(m_spellInfo->getRangeIndex());
408 if (spell_range != nullptr)
409 {
410 if (worldConfig.terrainCollision.isCollisionEnabled && spell_range->maxRange < 50000 && getEffectRadius(i) < 50000 && !obj->isItem())
411 {
412 float x = m_caster->GetPositionX(), y = m_caster->GetPositionY(), z = m_caster->GetPositionZ() + 0.5f;
413
414 //are we using a different location?
416 {
417 auto destination = m_targets.getDestination();
418 x = destination.x;
419 y = destination.y;
420 z = destination.z;
421 }
423 {
424 ///\todo Add support for this in arcemu
425 /*Object* lasttarget = NULL;
426 if (m_orderedObjects.size() > 0)
427 {
428 lasttarget = m_caster->getWorldMap()->_GetObject(m_orderedObjects[m_orderedObjects.size() - 1]);
429 if (lasttarget != NULL)
430 {
431 x = lasttarget->GetPositionX();
432 y = lasttarget->GetPositionY();
433 z = lasttarget->GetPositionZ();
434 }
435 }*/
436 }
437
439
440 if (!isInLOS)
441 return false;
442 }
443 }
444
445 return true;
446}
@ LINEOFSIGHT_ALL_CHECKS
Definition BaseMap.hpp:40
@ ATTRIBUTESEXC_TARGET_ONLY_PLAYERS
SpellDidHitResult
@ SPELL_DID_HIT_SUCCESS
@ SPELL_DID_HIT_REFLECT
@ SPELL_CAST_SUCCESS
@ SPELL_TARGET_AREA
Definition SpellTarget.h:37
@ SPELL_TARGET_AREA_CHAIN
Definition SpellTarget.h:40
@ UNIT_FLAG_IGNORE_PLAYER_COMBAT
SERVER_DECL WDB::WDBContainer< WDB::Structures::SpellRangeEntry > sSpellRangeStore
#define worldConfig
Definition World.h:245
uint32_t GetPhase() const
Definition Object.hpp:636
bool isItem() const
Definition Object.cpp:571
uint32_t getRangeIndex() const
uint8_t DidHit(uint32_t effindex, Unit *target)
SpellCastResult checkExplicitTarget(Object *target, uint32_t requiredTargetMask) const
Definition Spell.cpp:5705
void safeAddMissedTarget(uint64_t targetGuid, SpellDidHitResult hitResult, SpellDidHitResult extendedHitResult)
Definition Spell.cpp:5775
bool hasUnitFlags(uint32_t unitFlags) const
Definition Unit.cpp:1111
bool isInLineOfSight(LocationVector pos1, LocationVector pos2, uint32_t phasemask, LineOfSightChecks checks)
G3D::int16 z
G3D::int16 x
G3D::int16 y
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AddTime()

void Spell::AddTime ( uint32_t  type)

Definition at line 1101 of file Spell.Legacy.cpp.

1102{
1103 if (u_caster != nullptr)
1104 {
1105 if (getSpellInfo()->getInterruptFlags() & CAST_INTERRUPT_ON_DAMAGE_TAKEN)
1106 {
1108 return;
1109 }
1110
1111 float ch = 0;
1113 if (Util::checkChance(ch))
1114 return;
1115
1116 if (p_caster != nullptr)
1117 {
1119 return;
1120 }
1121 if (m_DelayStep == 2)
1122 return; //spells can only be delayed twice as of 3.0.2
1124 {
1125 // no pushback for some spells
1126 if ((getSpellInfo()->getInterruptFlags() & CAST_INTERRUPT_PUSHBACK) == 0)
1127 return;
1128 int32_t delay = 500; //0.5 second pushback
1129 ++m_DelayStep;
1130 m_timer += delay;
1131 if (m_timer > m_castTime)
1132 {
1133 delay -= (m_timer - m_castTime);
1135 if (delay < 0)
1136 delay = 1;
1137 }
1138
1140
1141 if (p_caster == nullptr)
1142 {
1143 //then it's a Creature
1144 u_caster->pauseMovement(delay);
1145 }
1146 //in case cast is delayed, make sure we do not exit combat
1147 else
1148 {
1149 // sEventMgr.ModifyEventTimeLeft(p_caster,EVENT_ATTACK_TIMEOUT,attackTimeoutInterval,true);
1150 // also add a new delay to offhand and main hand attacks to avoid cutting the cast short
1151
1152 // TODO: should spell cast time pushback reset swing timers again? -Appled
1153 //p_caster->delayMeleeAttackTimer(delay);
1154 }
1155 }
1156 else if (getSpellInfo()->getChannelInterruptFlags() != 48140)
1157 {
1158 int32_t delay = getDuration() / 4; //0.5 second push back
1159 ++m_DelayStep;
1160 m_timer -= delay;
1161 if (m_timer < 0)
1162 m_timer = 0;
1163 //else if (p_caster != nullptr)
1164 // TODO: should spell cast time pushback reset swing timers again? -Appled
1165 //p_caster->delayMeleeAttackTimer(-delay);
1166
1167 m_Delayed = true;
1168 if (m_timer > 0)
1170
1171 }
1172 }
1173}
@ CAST_INTERRUPT_ON_DAMAGE_TAKEN
@ CAST_INTERRUPT_PUSHBACK
@ SPELLMOD_NONINTERRUPT
@ SPELL_STATE_CASTING
virtual std::unique_ptr< WorldPacket > serialise()
void interruptSpell(uint32_t spellId=0, bool checkMeleeSpell=true)
Definition Object.cpp:701
const WoWGuid & GetNewGUID() const
Definition Object.hpp:335
virtual void sendMessageToSet(WorldPacket *data, bool self, bool myteam_only=false)
Definition Object.cpp:4490
uint32_t getChannelInterruptFlags() const
int32_t m_castTime
Definition Spell.hpp:124
void sendChannelUpdate(const uint32_t time, const uint32_t diff=0)
Definition Spell.cpp:4577
int32_t getDuration()
Definition Spell.cpp:5910
SpellState m_spellState
Definition Spell.hpp:336
int32_t m_timer
Definition Spell.hpp:125
uint32_t m_spellDelayResist[TOTAL_SPELL_SCHOOLS]
Definition Unit.hpp:1457
void pauseMovement(uint32_t timer=0, uint8_t slot=0, bool forced=true)
Definition Unit.cpp:3013
bool checkChance(uint32_t val)
Definition Random.cpp:56
signed int int32_t
Here is the call graph for this function:
Here is the caller graph for this function:

◆ addUsedSpellModifier()

void Spell::addUsedSpellModifier ( AuraEffectModifier const aurEff)

Definition at line 5851 of file Spell.cpp.

5852{
5853 for (const auto& usedMod : m_usedModifiers)
5854 {
5855 if (usedMod.first == aurEff)
5856 return;
5857 }
5858
5859 m_usedModifiers.insert(std::make_pair(aurEff, false));
5860}
Here is the caller graph for this function:

◆ ApplyAreaAura()

void Spell::ApplyAreaAura ( uint8_t  effectIndex)

Definition at line 710 of file SpellEffects.Legacy.cpp.

711{
712 if (!m_unitTarget || !m_unitTarget->isAlive()) return;
713 if (u_caster != m_unitTarget) return;
714
715 Aura* pAura = nullptr;
716 auto itr = m_pendingAuras.find(m_unitTarget->getGuid());
717 if (itr == m_pendingAuras.end())
718 {
719 auto auraHolder = sSpellMgr.newAura(getSpellInfo(), getDuration(), m_caster, m_unitTarget);
720
721 float r = getEffectRadius(effectIndex);
722
723 uint32_t eventtype = 0;
724
725 switch (m_spellInfo->getEffect(effectIndex))
726 {
729 break;
731 eventtype = EVENT_RAID_AREA_AURA_UPDATE;
732 break;
734 eventtype = EVENT_PET_AREA_AURA_UPDATE;
735 break;
738 break;
741 break;
742#if VERSION_STRING >= TBC
744 eventtype = EVENT_ENEMY_AREA_AURA_UPDATE; //Zyres: The same event as SPELL_EFFECT_APPLY_ENEMY_AREA_AURA? @Appled o.O
745#endif
746 break;
747 }
748
749 auraHolder->m_castedItemId = castedItemId;
750
751 if (!sEventMgr.HasEvent(auraHolder.get(), eventtype)) /* only add it once */
752 sEventMgr.AddEvent(auraHolder.get(), &Aura::EventUpdateAreaAura, effectIndex, r * r, eventtype, 1000, 0, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
753
754 const auto [itr, _] = m_pendingAuras.try_emplace(m_unitTarget->getGuid(), 0, std::move(auraHolder));
755 pAura = itr->second.aur.get();
756 }
757 else
758 {
759 pAura = itr->second.aur.get();
760 }
761
762 pAura->addAuraEffect(static_cast<AuraEffect>(getSpellInfo()->getEffectApplyAuraName(effectIndex)), damage, getSpellInfo()->getEffectMiscValue(effectIndex), effectPctModifier[effectIndex], isEffectDamageStatic[effectIndex], effectIndex);
763}
AuraEffect
@ EVENT_RAID_AREA_AURA_UPDATE
Definition EventMgr.h:94
@ EVENT_ENEMY_AREA_AURA_UPDATE
Definition EventMgr.h:97
@ EVENT_GROUP_AREA_AURA_UPDATE
Definition EventMgr.h:93
@ EVENT_FRIEND_AREA_AURA_UPDATE
Definition EventMgr.h:96
@ EVENT_PET_AREA_AURA_UPDATE
Definition EventMgr.h:95
@ EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT
Definition EventMgr.h:109
#define sEventMgr
Definition EventMgr.h:278
@ SPELL_EFFECT_APPLY_GROUP_AREA_AURA
@ SPELL_EFFECT_APPLY_FRIEND_AREA_AURA
@ SPELL_EFFECT_APPLY_ENEMY_AREA_AURA
@ SPELL_EFFECT_APPLY_PET_AREA_AURA
@ SPELL_EFFECT_APPLY_RAID_AREA_AURA
@ SPELL_EFFECT_APPLY_OWNER_AREA_AURA
void EventUpdateAreaAura(uint8_t effIndex, float r)
void addAuraEffect(AuraEffect auraEffect, int32_t damage, int32_t miscValue, float_t effectPctModifier, bool isStaticDamage, uint8_t effIndex, bool reapplying=false)
Definition SpellAura.cpp:47
uint32_t getEffect(uint8_t idx) const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ calculateEffect()

int32_t Spell::calculateEffect ( uint8_t  effIndex)

Definition at line 1469 of file Spell.cpp.

1470{
1472
1473 // Legacy script hook
1475
1476 const auto scriptResult = sScriptMgr.callScriptedSpellDoCalculateEffect(this, effIndex, &value);
1477
1478 // If effect damage was recalculated in script, send static damage in effect handlers
1479 // so for example spell power bonus won't get calculated twice
1482 return value;
1483
1484 if (getPlayerCaster() != nullptr)
1485 {
1486 const auto itr = getPlayerCaster()->m_spellOverrideMap.find(getSpellInfo()->getId());
1487 if (itr != getPlayerCaster()->m_spellOverrideMap.end())
1488 {
1489 for (auto scriptOverride = itr->second->begin(); scriptOverride != itr->second->end(); ++scriptOverride)
1490 {
1491 value += Util::getRandomUInt((*scriptOverride)->damage);
1492 }
1493 }
1494 }
1495
1496 if (getUnitCaster() != nullptr)
1497 {
1498 // Calculate spell and attack power bonus (must be calculated on launch, not on spell hit!)
1499 if (!isEffectDamageStatic[effIndex])
1500 {
1501 switch (getSpellInfo()->getEffect(effIndex))
1502 {
1504 value = static_cast<int32_t>(std::ceil(getUnitCaster()->applySpellDamageBonus(getSpellInfo(), value, 1.0f, false, this)));
1505 break;
1506 case SPELL_EFFECT_HEAL:
1508 value = static_cast<int32_t>(std::ceil(getUnitCaster()->applySpellHealingBonus(getSpellInfo(), value, 1.0f, false, this)));
1509 break;
1510 default:
1511 break;
1512 }
1513 }
1514
1515 // Save pct modifiers before applying so they can be readded properly later
1516 int32_t spellFlatMods = 0, spellPctMods = 100;
1517
1518 getUnitCaster()->getTotalSpellModifiers(SPELLMOD_ALL_EFFECTS, value, &spellFlatMods, &spellPctMods, getSpellInfo(), this, nullptr, true);
1520
1521 getUnitCaster()->getTotalSpellModifiers(SPELLMOD_EFFECT_BONUS, value, &spellFlatMods, &spellPctMods, getSpellInfo(), this, nullptr, true);
1523
1524 switch (effIndex)
1525 {
1526 case 0:
1527 getUnitCaster()->getTotalSpellModifiers(SPELLMOD_EFFECT_1, value, &spellFlatMods, &spellPctMods, getSpellInfo(), this, nullptr, true);
1529 break;
1530 case 1:
1531 getUnitCaster()->getTotalSpellModifiers(SPELLMOD_EFFECT_2, value, &spellFlatMods, &spellPctMods, getSpellInfo(), this, nullptr, true);
1533 break;
1534 case 2:
1535 getUnitCaster()->getTotalSpellModifiers(SPELLMOD_EFFECT_3, value, &spellFlatMods, &spellPctMods, getSpellInfo(), this, nullptr, true);
1537 break;
1538 default:
1539 break;
1540 }
1541
1542 effectPctModifier[effIndex] = spellPctMods / 100.0f;
1543 }
1544 else if (getItemCaster() != nullptr && getUnitTarget() != nullptr)
1545 {
1546 // Apply spell modifiers from the item owner
1547 const auto itemCreator = getUnitTarget()->getWorldMapUnit(getItemCaster()->getCreatorGuid());
1548 if (itemCreator != nullptr)
1549 {
1551 itemCreator->applySpellModifiers(SPELLMOD_EFFECT_BONUS, &value, getSpellInfo(), this);
1552 }
1553 }
1554
1555 return value;
1556}
#define sScriptMgr
@ SPELL_EFFECT_HEAL
@ SPELL_EFFECT_HEAL_MECHANICAL
@ SPELL_EFFECT_SCHOOL_DAMAGE
@ SPELLMOD_EFFECT_BONUS
@ SPELLMOD_ALL_EFFECTS
@ SPELLMOD_EFFECT_3
@ SPELLMOD_EFFECT_1
@ SPELLMOD_EFFECT_2
SpellOverrideMap m_spellOverrideMap
Definition Player.hpp:868
int32_t calculateEffectValue(uint8_t effIndex, Unit *unitCaster=nullptr, Item *itemCaster=nullptr, SpellForcedBasePoints forcedBasePoints=SpellForcedBasePoints()) const
Unit * getUnitTarget() const
Definition Spell.cpp:5682
virtual int32_t DoCalculateEffect(uint32_t i, Unit *target, int32_t value)
void getTotalSpellModifiers(SpellModifierType modType, T baseValue, int32_t *flatMod, int32_t *pctMod, SpellInfo const *spellInfo, Spell *castingSpell=nullptr, Aura *castingAura=nullptr, bool checkOnly=false)
Definition Unit.cpp:4480
uint32_t getRandomUInt(uint32_t end)
Definition Random.cpp:32
Here is the call graph for this function:
Here is the caller graph for this function:

◆ calculateJumpSpeeds()

void Spell::calculateJumpSpeeds ( Unit unitCaster,
SpellInfo const spellInfo,
uint8_t  i,
float  dist,
float &  speedXY,
float &  speedZ 
)

Definition at line 3000 of file Spell.Legacy.cpp.

3001{
3002 float runSpeed = unitCaster->getSpeedRate(TYPE_RUN, false);
3003
3004 if (Creature* creature = unitCaster->ToCreature())
3005 runSpeed *= creature->GetCreatureProperties()->run_speed;
3006
3007 float multiplier = m_spellInfo->getEffectMultipleValue(i);
3008 if (multiplier <= 0.0f)
3009 multiplier = 1.0f;
3010
3011 speedXY = std::min(runSpeed * 3.0f * multiplier, std::max(28.0f, unitCaster->getSpeedRate(TYPE_RUN, false) * 4.0f));
3012
3013 float duration = dist / speedXY;
3014 float durationSqr = duration * duration;
3015 float minHeight = spellInfo->getEffectMiscValue(i) ? spellInfo->getEffectMiscValue(i) / 10.0f : 0.5f; // Lower bound is blizzlike
3016 float maxHeight = spellInfo->getEffectMiscValueB(i) ? spellInfo->getEffectMiscValueB(i) / 10.0f : 1000.0f; // Upper bound is unknown
3017 float height;
3018
3019 if (durationSqr < minHeight * 8 / MovementMgr::gravity)
3020 height = minHeight;
3021 else if (durationSqr > maxHeight * 8 / MovementMgr::gravity)
3022 height = maxHeight;
3023 else
3024 height = MovementMgr::gravity * durationSqr / 8;
3025
3026 speedZ = std::sqrt(2 * MovementMgr::gravity * height);
3027}
@ TYPE_RUN
Creature * ToCreature()
Definition Object.hpp:393
float getEffectMultipleValue(uint8_t idx) const
float getSpeedRate(UnitSpeedType type, bool current) const
Definition Unit.cpp:2549
SERVER_DECL float gravity
Here is the call graph for this function:
Here is the caller graph for this function:

◆ calculatePowerCost()

uint32_t Spell::calculatePowerCost ( )
private

Definition at line 5595 of file Spell.cpp.

5596{
5597 // Null for non-unit casters
5598 if (u_caster == nullptr)
5599 return 0;
5600
5601 auto powerCost = getSpellInfo()->getBasePowerCost(u_caster);
5602
5603 // Use first school found from mask
5604 const auto spellSchool = getSpellInfo()->getFirstSchoolFromSchoolMask();
5605
5606 // Include power cost modifiers from that school
5607 powerCost += u_caster->getPowerCostModifier(spellSchool);
5608
5609 // Special case for rogue's Shiv - power cost depends on the speed of offhand weapon
5610 if (getSpellInfo()->getAttributesExD() & ATTRIBUTESEXD_SHIV)
5611 {
5612 // Formula seems to be 20 + offhand weapon speed in seconds * 10
5613 powerCost += u_caster->getBaseAttackTime(OFFHAND) / 100;
5614 }
5615
5616 // Apply modifiers
5618
5619 // Include power cost multipliers from that school
5620 powerCost = static_cast<int32_t>(powerCost * (1.0f + u_caster->getPowerCostMultiplier(spellSchool)));
5621
5622 if (powerCost < 0)
5623 powerCost = 0;
5624
5625 return static_cast<uint32_t>(powerCost);
5626}
@ ATTRIBUTESEXD_SHIV
@ SPELLMOD_COST
@ OFFHAND
uint8_t getFirstSchoolFromSchoolMask() const
int32_t getBasePowerCost(Unit *caster) const
float getPowerCostMultiplier(uint16_t school) const
Definition Unit.cpp:1615
uint32_t getBaseAttackTime(uint8_t slot) const
Definition Unit.cpp:1233
uint32_t getPowerCostModifier(uint16_t school) const
Definition Unit.cpp:1602
Here is the call graph for this function:
Here is the caller graph for this function:

◆ canAttackCreatureType()

bool Spell::canAttackCreatureType ( Creature target) const
private

Definition at line 6002 of file Spell.cpp.

6003{
6004 // Skip check for Grounding Totem
6005 if (target->getCreatedBySpellId() == 8177)
6006 return true;
6007
6008 const auto typeMask = getSpellInfo()->getTargetCreatureType();
6009 const auto mask = 1 << (target->GetCreatureProperties()->Type - 1);
6010 return !(target->GetCreatureProperties()->Type != 0 && typeMask != 0 && (typeMask & mask) == 0);
6011}
CreatureProperties const * GetCreatureProperties()
uint32_t getTargetCreatureType() const
uint32_t getCreatedBySpellId() const
Definition Unit.cpp:1430
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CanCast()

uint8_t Spell::CanCast ( bool  )

Object cast checks

Check for valid targets

Check for valid location

Player caster checks

On taxi check

Is mounted check

check if spell is allowed while we have a battleground flag

Targeted Unit Checks

Definition at line 1702 of file Spell.Legacy.cpp.

1703{
1704 /**
1705 * Object cast checks
1706 */
1707 if (m_caster && m_caster->IsInWorld())
1708 {
1710
1711 /**
1712 * Check for valid targets
1713 */
1714 if (target)
1715 {
1716 switch (getSpellInfo()->getId())
1717 {
1718 // SPELL_HASH_DEATH_PACT
1719 case 17471:
1720 case 17698:
1721 case 48743:
1722 case 51956:
1723 {
1724 if (target->getSummonedByGuid() != m_caster->getGuid())
1726 } break;
1727 }
1728 }
1729
1730 /**
1731 * Check for valid location
1732 */
1733 if (getSpellInfo()->getId() == 32146)
1734 {
1736 if (corpse != nullptr)
1737 if (m_caster->CalcDistance(m_caster, corpse) > 5)
1738 return SPELL_FAILED_NOT_HERE;
1739 }
1740 else if (getSpellInfo()->getId() == 39246)
1741 {
1743 if (cleft == nullptr || cleft->isAlive())
1744 return SPELL_FAILED_NOT_HERE;
1745 }
1746 else if (getSpellInfo()->getId() == 30988)
1747 {
1749 if (corpse != nullptr)
1750 if (m_caster->CalcDistance(m_caster, corpse) > 5 || corpse->isAlive())
1751 return SPELL_FAILED_NOT_HERE;
1752 }
1753 else if (getSpellInfo()->getId() == 43723)
1754 {
1756 if (abysal != nullptr)
1757 {
1758 if (!abysal->isAlive())
1759 if (!(p_caster->getItemInterface()->GetItemCount(31672) > 1 && p_caster->getItemInterface()->GetItemCount(31673) > 0 && p_caster->CalcDistance(p_caster, abysal) < 10))
1760 return SPELL_FAILED_NOT_HERE;
1761 }
1762 else
1763 return SPELL_FAILED_NOT_HERE;
1764 }
1765 else if (getSpellInfo()->getId() == 32307)
1766 {
1768 if (kilsorrow == nullptr || kilsorrow->isAlive() || p_caster->CalcDistance(p_caster, kilsorrow) > 1)
1769 return SPELL_FAILED_NOT_HERE;
1770 if (kilsorrow->getEntry() != 17147 && kilsorrow->getEntry() != 17148 && kilsorrow->getEntry() != 18397 && kilsorrow->getEntry() != 18658 && kilsorrow->getEntry() != 17146)
1771 return SPELL_FAILED_NOT_HERE;
1772 }
1773 }
1774
1775 /**
1776 * Player caster checks
1777 */
1778 if (p_caster)
1779 {
1780 /**
1781 * On taxi check
1782 */
1783 if (!p_caster->isOnTaxi())
1784 {
1785 if (getSpellInfo()->getId() == 33836 || getSpellInfo()->getId() == 45072 || getSpellInfo()->getId() == 45115 || getSpellInfo()->getId() == 31958)
1786 return SPELL_FAILED_NOT_HERE;
1787 }
1788
1789 /**
1790 * Is mounted check
1791 */
1792 if (!p_caster->isMounted())
1793 {
1794 if (getSpellInfo()->getId() == 25860) // Reindeer Transformation
1796 }
1797
1798 /**
1799 * check if spell is allowed while we have a battleground flag
1800 */
1801 if (p_caster->hasBgFlag())
1802 {
1803 switch (getSpellInfo()->getId())
1804 {
1805 // stealth spells
1806 case 1784:
1807 case 1785:
1808 case 1786:
1809 case 1787:
1810 case 5215:
1811 case 6783:
1812 case 9913:
1813 case 1856:
1814 case 1857:
1815 case 26889:
1816 {
1817 if (const auto battleground = p_caster->getBattleground())
1818 {
1819 if (battleground->getType() == BattlegroundDef::TYPE_WARSONG_GULCH)
1820 battleground->HookOnFlagDrop(p_caster);
1821 else if (battleground->getType() == BattlegroundDef::TYPE_EYE_OF_THE_STORM)
1822 battleground->HookOnFlagDrop(p_caster);
1823 }
1824 break;
1825 }
1826 }
1827 }
1828 }
1829
1830 /**
1831 * Targeted Unit Checks
1832 */
1834 {
1836
1837 if (target)
1838 {
1839 // \todo Replace this awful hacks with a better solution
1840 // Nestlewood Owlkin - Quest 9303
1841 if (getSpellInfo()->getId() == 29528 && target->isCreature() && target->getEntry() == 16518)
1842 {
1843 if (target->isRooted())
1844 {
1846 }
1847
1848 target->setTargetGuid(p_caster->getGuid());
1849 return SPELL_CAST_SUCCESS;
1850 }
1851
1852 // Lazy Peons - Quest 5441
1853 if (getSpellInfo()->getId() == 19938 && target->isCreature() && target->getEntry() == 10556)
1854 {
1855 if (!target->hasAurasWithId(17743))
1856 {
1858 }
1859
1860 return SPELL_CAST_SUCCESS;
1861 }
1862
1863 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1864
1865 // scripted spell stuff
1866 switch (getSpellInfo()->getId())
1867 {
1868 case 603: //curse of doom, can't be cast on players
1869 case 30910:
1870 case 47867: // Curse of doom rank 4
1871 {
1872 if (target->isPlayer())
1874 }
1875 break;
1876 case 13907: // Smite Demon
1877 {
1878 if (target->isPlayer() || target->getClass() != TARGET_TYPE_DEMON)
1880 }
1881 break;
1882
1883 default:
1884 break;
1885 }
1886
1887 // if the target is not the unit caster and not the masters pet
1888 if (target != u_caster && !m_caster->isPet())
1889 {
1890
1891 /***********************************************************
1892 * Inface checks, these are checked in 2 ways
1893 * 1e way is check for damage type, as 3 is always ranged
1894 * 2e way is trough the data in the extraspell db
1895 *
1896 **********************************************************/
1897
1898 uint32_t facing_flags = getSpellInfo()->getFacingCasterFlags();
1899
1900 // Holy shock need enemies be in front of caster
1901 switch (getSpellInfo()->getId())
1902 {
1903 //SPELL_HASH_HOLY_SHOCK
1904 case 20473:
1905 case 20929:
1906 case 20930:
1907 case 25902:
1908 case 25903:
1909 case 25911:
1910 case 25912:
1911 case 25913:
1912 case 25914:
1913 case 27174:
1914 case 27175:
1915 case 27176:
1916 case 32771:
1917 case 33072:
1918 case 33073:
1919 case 33074:
1920 case 35160:
1921 case 36340:
1922 case 38921:
1923 case 48820:
1924 case 48821:
1925 case 48822:
1926 case 48823:
1927 case 48824:
1928 case 48825:
1929 case 66114:
1930 case 68014:
1931 case 68015:
1932 case 68016:
1933 {
1934 if (getSpellInfo()->getEffect(0) == SPELL_EFFECT_DUMMY && !u_caster->isFriendlyTo(target))
1936 } break;
1937 }
1938 }
1939
1940 // fishing spells
1941 if (getSpellInfo()->getEffectImplicitTargetA(0) == EFF_TARGET_SELF_FISHING) //||
1942 //GetProto()->EffectImplicitTargetA[1] == EFF_TARGET_SELF_FISHING ||
1943 //GetProto()->EffectImplicitTargetA[2] == EFF_TARGET_SELF_FISHING)
1944 {
1946 if (entry == GO_FISHING_BOBBER)
1947 {
1949 float minDist = m_spellInfo->getMinRange(true);
1950 float maxDist = m_spellInfo->getMaxRange(true);
1951 float posx = 0, posy = 0, posz = 0;
1952 float dist = Util::getRandomFloat(minDist, maxDist);
1953
1954 float angle = Util::getRandomFloat(0.0f, 1.0f) * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f);
1955 m_caster->getClosePoint(posx, posy, posz, 0.388999998569489f, dist, angle);
1956
1957 float ground = m_caster->getMapHeight(LocationVector(posx, posy, posz));
1958 float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
1959
1960 LiquidData liquidData;
1961 if (map->getLiquidStatus(m_caster->GetPhase(), LocationVector(posx, posy, posz), MAP_ALL_LIQUIDS, &liquidData, m_caster->getCollisionHeight()))
1962 liquidLevel = liquidData.level;
1963
1964 if (liquidLevel <= ground)
1966
1967 if (ground + 0.75 > liquidLevel)
1968#if VERSION_STRING > Classic
1969 return SPELL_FAILED_TOO_SHALLOW;
1970#else
1972#endif
1973
1974 // if we are already fishing, don't cast it again
1978
1979 m_targets.setDestination(LocationVector(posx, posy, liquidLevel));
1980 }
1981 }
1982
1983 //check if we are trying to stealth or turn invisible but it is not allowed right now
1985 {
1986 uint32_t faerieFireFeral[] =
1987 {
1988 //SPELL_HASH_FAERIE_FIRE__FERAL_
1989 16857,
1990 60089,
1991 0
1992 };
1993
1994 //if we have Faerie Fire, we cannot stealth or turn invisible
1995 uint32_t faerieFire[] =
1996 {
1997 //SPELL_HASH_FAERIE_FIRE
1998 770,
1999 6950,
2000 13424,
2001 13752,
2002 16498,
2003 20656,
2004 21670,
2005 25602,
2006 32129,
2007 65863,
2008 0
2009 };
2010
2011 if (u_caster->getAuraWithId(faerieFire) || u_caster->hasAurasWithId(faerieFireFeral))
2013 }
2014 }
2015 }
2016
2017 // no problems found, so we must be ok
2018 return SPELL_CAST_SUCCESS;
2019}
#define M_PI
#define VMAP_INVALID_HEIGHT_VALUE
@ EFF_TARGET_SELF_FISHING
@ SPELL_FAILED_NOT_HERE
@ SPELL_FAILED_TARGET_IS_PLAYER
@ SPELL_FAILED_NOT_FISHABLE
@ SPELL_FAILED_BAD_TARGETS
@ SPELL_FAILED_ONLY_MOUNTED
@ SPELL_FAILED_SPELL_IN_PROGRESS
@ SPELL_FAILED_SPELL_UNAVAILABLE
@ SPELL_INFRONT_STATUS_REQUIRE_INFRONT
@ TARGET_TYPE_DEMON
#define GO_FISHING_BOBBER
Definition Spell.hpp:48
@ MAP_ALL_LIQUIDS
static const unsigned char map[256]
uint32_t GetItemCount(uint32_t itemid, bool IncBank=false)
Finds item ammount on inventory, banks not included.
Creature * getCreatureNearestCoords(float x, float y, float z=0.0f, uint32_t Entry=0)
void getClosePoint(float &x, float &y, float &z, float size, float distance2d=0, float relAngle=0)
Definition Object.cpp:4811
bool isFriendlyTo(Object *target)
Definition Object.cpp:4047
float getMapHeight(LocationVector pos, bool vmap=true, float distanceToSearch=50.0f)
Definition Object.cpp:5032
uint32_t getEntry() const
Definition Object.cpp:382
virtual float getCollisionHeight() const
Definition Object.hpp:574
bool isOnTaxi() const
Definition Player.cpp:10775
Object * getSummonedObject() const
Definition Player.cpp:12704
bool hasBgFlag() const
Definition Player.cpp:8577
Battleground * getBattleground() const
Definition Player.cpp:8546
uint32_t getFacingCasterFlags() const
float_t getMinRange(bool friendly=false) const
int32_t getEffectMiscValue(uint8_t idx) const
bool IsStealthSpell()
bool IsInvisibilitySpell()
bool hasAurasWithId(uint32_t auraId) const
Definition Unit.cpp:5004
Aura * getAuraWithId(uint32_t spell_id) const
Definition Unit.cpp:4849
uint8_t getClass() const
Definition Unit.cpp:456
bool isRooted() const
Definition Unit.cpp:1945
uint64_t getSummonedByGuid() const
Definition Unit.cpp:394
bool isMounted() const
Definition Unit.cpp:8541
void setTargetGuid(uint64_t guid)
Definition Unit.cpp:401
MapScriptInterface * getInterface()
Unit * getUnit(const uint64_t &guid)
float getRandomFloat(float end)
Definition Random.cpp:44
Here is the call graph for this function:
Here is the caller graph for this function:

◆ canCast()

SpellCastResult Spell::canCast ( const bool  secondCheck,
uint32_t parameter1,
uint32_t parameter2 
)
virtual

\ todo: need to check for units as well, like when player is controlling a creature

Reimplemented in FireNova, and DeathCoilSpell.

Definition at line 1560 of file Spell.cpp.

1561{
1562 ////////////////////////////////////////////////////////
1563 // Caster checks
1564
1565 if (p_caster != nullptr)
1566 {
1567 if (!m_triggeredSpell)
1568 {
1569 if (!getSpellInfo()->isPassive())
1570 {
1571#if VERSION_STRING >= WotLK
1572 // You can't cast other spells if you have the player flag preventing cast
1573 if (p_caster->hasPlayerFlags(PLAYER_FLAG_PREVENT_SPELL_CAST))
1575#endif
1576
1577 // Check for cooldown
1579 {
1582 else
1584 }
1585 }
1586
1587 // Check for global cooldown
1588 // but do not check it on second check
1589 ///\ todo: need to check for units as well, like when player is controlling a creature
1590 if (!secondCheck && p_caster->hasSpellGlobalCooldown(getSpellInfo()))
1591 {
1594 else
1596 }
1597 }
1598
1599#if VERSION_STRING >= WotLK
1601 {
1602 *parameter1 = SPELL_EXTRA_ERROR_GM_ONLY;
1603 return SPELL_FAILED_CUSTOM_ERROR;
1604 }
1605#endif
1606
1607 // Battleground checks
1609 {
1610#if VERSION_STRING >= TBC
1611 // Arena checks
1613 {
1614 // Spells with longer than 10 minute cooldown cannot be casted in arena
1616 if (getSpellInfo()->getAttributesExD() & ATTRIBUTESEXD_NOT_IN_ARENAS || (spellCooldown > 10 * MINUTE * IN_MILLISECONDS && !(getSpellInfo()->getAttributesExD() & ATTRIBUTESEXD_NOT_IN_ARENAS)))
1617 return SPELL_FAILED_NOT_IN_ARENA;
1618 }
1619#endif
1620
1621 // If battleground has ended, don't allow spell casting
1624 }
1625 else if (getSpellInfo()->getAttributesExC() & ATTRIBUTESEXC_BG_ONLY)
1626 {
1628 }
1629
1630 // Movement check
1631 if (p_caster->isMoving())
1632 {
1633 // No need to check for other interrupt flags, client does that for us
1634 // Also don't cast first ranged autorepeat spell if we're moving but activate it
1635 // TODO: Missing cata checks, in cata you can cast some spells while moving
1636 if (getSpellInfo()->isRangedAutoRepeat() || getSpellInfo()->getAuraInterruptFlags() & AURA_INTERRUPT_ON_STAND_UP)
1637 return SPELL_FAILED_MOVING;
1638 }
1639
1640 // Prevent casting while sitting unless the spell allows it
1643 }
1644
1645 if (u_caster != nullptr)
1646 {
1647 // Check if caster is alive
1648 if (!u_caster->isAlive() && !(getSpellInfo()->getAttributes() & ATTRIBUTES_DEAD_CASTABLE || (m_triggeredSpell && !m_triggeredByAura)))
1649 {
1650 // but allow casting while in Spirit of Redemption form
1653 }
1654
1655 // Check if spell requires caster to be in combat
1658
1659 auto requireCombat = true;
1660#if VERSION_STRING >= WotLK
1662 {
1663 for (const auto& aurEff : getUnitCaster()->getAuraEffectList(SPELL_AURA_IGNORE_TARGET_AURA_STATE))
1664 {
1665 if (aurEff->getAura()->getSpellInfo()->isAuraEffectAffectingSpell(aurEff->getAuraEffectType(), getSpellInfo()))
1666 {
1667 // Warrior's Overpower uses "combo points" based on dbc data
1668 // This allows usage of Overpower if we have an affecting aura (i.e. Taste for Blood)
1669 m_requiresCP = false;
1670
1671 // All these aura effects use effect index 0
1672 // Allow Warrior's Charge to be casted on combat if caster has Juggernaut or Warbringer talent
1673 if (aurEff->getAura()->getSpellInfo()->getEffectMiscValue(0) == 1)
1674 {
1675 requireCombat = false;
1676 break;
1677 }
1678 }
1679 }
1680 }
1681#endif
1682
1683 // Caster's aura state requirements
1684 if (getSpellInfo()->getCasterAuraState() > 0 && !u_caster->hasAuraState(static_cast<AuraState>(getSpellInfo()->getCasterAuraState()), getSpellInfo(), u_caster))
1686 if (getSpellInfo()->getCasterAuraStateNot() > 0 && u_caster->hasAuraState(static_cast<AuraState>(getSpellInfo()->getCasterAuraStateNot()), getSpellInfo(), u_caster))
1688
1689 // Caster's aura spell requirements
1690 if (getSpellInfo()->getCasterAuraSpell() > 0 && !u_caster->hasAurasWithId(getSpellInfo()->getCasterAuraSpell()))
1692 if (getSpellInfo()->getCasterAuraSpellNot() > 0)
1693 {
1694 // TODO: I leave this here for now (from my old work), but this really should be moved to wotlk spellscript -Appled
1695 // Paladin's Avenging Wrath / Forbearance thing
1696 if (getSpellInfo()->getCasterAuraSpellNot() == 61988)
1697 {
1698 if (u_caster->hasAurasWithId(61987))
1700 }
1701 else if (u_caster->hasAurasWithId(getSpellInfo()->getCasterAuraSpellNot()))
1702 {
1704 }
1705 }
1706
1707 if (!m_triggeredSpell)
1708 {
1709 // Out of combat spells should not be able to be casted in combat
1710 if (requireCombat && (getSpellInfo()->getAttributes() & ATTRIBUTES_REQ_OOC) && u_caster->getCombatHandler().isInCombat())
1712
1713 if (!secondCheck)
1714 {
1715 // Shapeshift check
1716#if VERSION_STRING >= WotLK
1717 auto hasIgnoreShapeshiftAura = false;
1718 for (const auto& aurEff : getUnitCaster()->getAuraEffectList(SPELL_AURA_IGNORE_SHAPESHIFT))
1719 {
1720 // If aura has ignore shapeshift type, you can use spells regardless of stance / form
1721 // Auras with this type: Shadow Dance, Metamorphosis, Warbringer (in 3.3.5a)
1722 if (aurEff->getAura()->getSpellInfo()->isAuraEffectAffectingSpell(SPELL_AURA_IGNORE_SHAPESHIFT, getSpellInfo()))
1723 {
1724 hasIgnoreShapeshiftAura = true;
1725 break;
1726 }
1727 }
1728
1729 if (!hasIgnoreShapeshiftAura)
1730#endif
1731 {
1733 if (shapeError != SPELL_CAST_SUCCESS)
1734 return shapeError;
1735
1736 // Stealth check
1739 }
1740 }
1741 }
1742 }
1743
1744 // Indoor and outdoor specific spells
1745 if (worldConfig.terrainCollision.isCollisionEnabled)
1746 {
1747 if (getSpellInfo()->getAttributes() & ATTRIBUTES_ONLY_OUTDOORS &&
1750
1751 if (getSpellInfo()->getAttributes() & ATTRIBUTES_ONLY_INDOORS &&
1754 }
1755
1756 ////////////////////////////////////////////////////////
1757 // Target checks
1758
1759 const auto explicitTargetMask = getSpellInfo()->getRequiredTargetMask(true);
1760
1761 // Check explicit gameobject target
1763 {
1765 const auto targetCheck = checkExplicitTarget(objTarget, explicitTargetMask);
1766 if (targetCheck != SPELL_CAST_SUCCESS)
1767 return targetCheck;
1768 }
1769
1770 // Unit target
1771 const auto target = m_caster->getWorldMapUnit(m_targets.getUnitTargetGuid());
1772 if (target != nullptr)
1773 {
1774 // Check explicit unit target
1775 // but skip spells with pet target here
1776 if (!getSpellInfo()->hasTargetType(EFF_TARGET_PET))
1777 {
1778 const auto targetCheck = checkExplicitTarget(target, explicitTargetMask);
1779 if (targetCheck != SPELL_CAST_SUCCESS)
1780 return targetCheck;
1781 }
1782
1783 // Target's aura state requirements
1784 if (!m_triggeredSpell && getSpellInfo()->getTargetAuraState() > 0 && !target->hasAuraState(static_cast<AuraState>(getSpellInfo()->getTargetAuraState()), getSpellInfo(), u_caster))
1786 if (getSpellInfo()->getTargetAuraStateNot() > 0 && target->hasAuraState(static_cast<AuraState>(getSpellInfo()->getTargetAuraState()), getSpellInfo(), u_caster))
1788
1789 // Target's aura spell requirements
1790 if (getSpellInfo()->getTargetAuraSpell() > 0 && !target->hasAurasWithId(getSpellInfo()->getTargetAuraSpell()))
1792 if (getSpellInfo()->getTargetAuraSpellNot() > 0)
1793 {
1794 // TODO: I leave this here for now (from my old work), but this really should be moved to wotlk spellscript -Appled
1795 // Paladin's Avenging Wrath / Forbearance thing
1796 if (getSpellInfo()->getTargetAuraSpellNot() == 61988)
1797 {
1798 if (target->hasAurasWithId(61987))
1800 }
1801 else if (target->hasAurasWithId(getSpellInfo()->getTargetAuraSpellNot()))
1802 {
1804 }
1805 }
1806
1807 if (target->isCorpse())
1808 {
1809 // Player can't cast spells on corpses with bones only left
1810 const auto targetCorpse = sObjectMgr.getCorpseByOwner(target->getGuidLow());
1811 if (targetCorpse == nullptr || !targetCorpse->IsInWorld() || targetCorpse->getCorpseState() == CORPSE_STATE_BONES)
1813 }
1814
1815 if (getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_CANT_TARGET_SELF && m_caster == target)
1817
1818 // Check if spell requires target to be out of combat
1819 if (getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_REQ_OOC_TARGET && target->getCombatHandler().isInCombat())
1821
1822 if (!(getSpellInfo()->getAttributesExF() & ATTRIBUTESEXF_CAN_TARGET_INVISIBLE) && (u_caster != nullptr && !u_caster->canSee(target)))
1824
1825 if (getSpellInfo()->getAttributesExC() & ATTRIBUTESEXC_TARGET_ONLY_GHOSTS)
1826 {
1827 if (!target->hasAuraWithAuraEffect(SPELL_AURA_GHOST))
1829 }
1830 else
1831 {
1832 if (target->hasAuraWithAuraEffect(SPELL_AURA_GHOST))
1834 }
1835
1836 // Check for max level
1837 if (getSpellInfo()->getMaxTargetLevel() != 0 && getSpellInfo()->getMaxTargetLevel() < target->getLevel())
1839
1840 // Check combo points
1841 if (m_requiresCP && getPlayerCaster() != nullptr)
1842 {
1843 if (!(getPlayerCaster()->getComboPoints() > 0 && getPlayerCaster()->getComboPointTarget() == target->getGuid()))
1845 }
1846
1847 if (m_caster != target)
1848 {
1849 if (p_caster != nullptr)
1850 {
1851 // Check if caster can attack this creature type
1852 if (target->isCreature())
1853 {
1854 if (!canAttackCreatureType(dynamic_cast<Creature*>(target)))
1856 }
1857
1858 // Check if target is already tagged
1859 // Several spells cannot be casted at already tagged creatures
1860 // TODO: implement this error message for skinning, mining and herbalism (mining and herbalism cata only)
1861 if (getSpellInfo()->getAttributesExB() & ATTRIBUTESEXB_CANT_TARGET_TAGGED && target->isTagged() && !target->isTaggedByPlayerOrItsGroup(p_caster))
1863
1864 // GM flagged players should be immune to other players' casts, but not their own
1865 if (target->isPlayer() && (dynamic_cast<Player*>(target)->hasPlayerFlags(PLAYER_FLAG_GM) || dynamic_cast<Player*>(target)->m_isGmInvisible))
1866 {
1867#if VERSION_STRING == Classic
1869#else
1870 return SPELL_FAILED_BM_OR_INVISGOD;
1871#endif
1872 }
1873
1874 // Check if target can be tamed
1875 if (getSpellInfo()->getAttributesExB() & ATTRIBUTESEXB_TAME_BEAST)
1876 {
1878 // If spell is triggered, target may need to be picked manually
1879 if (targetUnit == nullptr)
1880 {
1881 if (p_caster->getTargetGuid() != 0)
1883 }
1884
1885 if (targetUnit == nullptr)
1886 {
1889 }
1890
1891 const auto creatureTarget = targetUnit->isCreature() ? dynamic_cast<Creature*>(targetUnit) : nullptr;
1892 if (creatureTarget == nullptr)
1893 {
1896 }
1897
1898 if (!creatureTarget->isAlive())
1899 {
1902 }
1903
1904 if (creatureTarget->isPet())
1905 {
1908 }
1909
1910 if (creatureTarget->GetCreatureProperties()->Type != UNIT_TYPE_BEAST || creatureTarget->GetCreatureProperties()->Family == 0 || !(creatureTarget->GetCreatureProperties()->typeFlags & CREATURE_FLAG1_TAMEABLE))
1911 {
1914 }
1915
1916 if (p_caster->getClass() != HUNTER)
1917 {
1920 }
1921
1922 if (creatureTarget->getLevel() > p_caster->getLevel())
1923 {
1926 }
1927
1928 if (p_caster->getPet() != nullptr || !p_caster->findFreeActivePetSlot().has_value())
1929 {
1932 }
1933
1935 {
1938 }
1939
1940#if VERSION_STRING >= WotLK
1941 // Check for Beast Mastery spell with exotic creatures
1942 if (!p_caster->hasAuraWithAuraEffect(SPELL_AURA_ALLOW_TAME_PET_TYPE) && creatureTarget->IsExotic())
1943 {
1946 }
1947#endif
1948
1949 // All good so far, check creature's family
1950 const auto creatureFamily = sCreatureFamilyStore.lookupEntry(creatureTarget->GetCreatureProperties()->Family);
1951 if (creatureFamily == nullptr || creatureFamily->tameable == 0)
1952 {
1955 }
1956 }
1957 }
1958
1959 // Do facing checks only for unit casters
1960 if (u_caster != nullptr)
1961 {
1962 // Target must be in front of caster
1963 // Check for generic ranged spells as well, if caster is player
1964 if (getSpellInfo()->getFacingCasterFlags() == SPELL_INFRONT_STATUS_REQUIRE_INFRONT || getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_REQ_FACING_TARGET || (getPlayerCaster() != nullptr && getSpellInfo()->getDmgClass() == SPELL_DMG_TYPE_RANGED))
1965 {
1966 if (!u_caster->isInFront(target))
1968 }
1969
1970 // Target must be behind caster
1971 if (getSpellInfo()->getFacingCasterFlags() == SPELL_INFRONT_STATUS_REQUIRE_INBACK)
1972 {
1973 if (u_caster->isInFront(target))
1975 }
1976
1977 // Caster must be behind the target
1978 if (getSpellInfo()->getAttributesExB() & ATTRIBUTESEXB_REQ_BEHIND_TARGET && getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_REQ_FACING_TARGET && target->isInFront(u_caster))
1979 {
1980 // Throw spell has these attributes in 3.3.5a, ignore
1981 if (getSpellInfo()->getId() != SPELL_RANGED_THROW
1982#if VERSION_STRING >= TBC
1983 // Druid - Pounce, "Patch 2.0.3 - Pounce no longer requires the druid to be behind the target."
1984 && !(getSpellInfo()->getSpellFamilyName() == SPELLFAMILY_DRUID && getSpellInfo()->getSpellFamilyFlags(0) == 0x20000)
1985#endif
1986#if VERSION_STRING >= WotLK
1987 // Rogue - Mutilate, "Patch 3.0.2 - Mutilate no longer requires you be behind the target."
1988 && !(getSpellInfo()->getSpellFamilyName() == SPELLFAMILY_ROGUE && getSpellInfo()->getSpellFamilyFlags(1) == 0x200000)
1989#endif
1990 )
1992 }
1993
1994 // Caster must be in front of target
1995 if (getSpellInfo()->getAttributes() == (ATTRIBUTES_ABILITY | ATTRIBUTES_NOT_SHAPESHIFT | ATTRIBUTES_UNK20 | ATTRIBUTES_STOP_ATTACK) && !target->isInFront(u_caster))
1997 }
1998
1999 // Check if spell can be casted on dead target
2001 getSpellInfo()->getAttributesExB() & ATTRIBUTESEXB_CAN_BE_CASTED_ON_DEAD_TARGET) && !target->isAlive())
2003
2004 if (target->hasAuraWithAuraEffect(SPELL_AURA_SPIRIT_OF_REDEMPTION))
2006
2007 // Line of Sight check
2008 if (!m_triggeredSpell && worldConfig.terrainCollision.isCollisionEnabled)
2009 {
2010 if (m_caster->IsInWorld() && !(getSpellInfo()->getAttributesExB() & ATTRIBUTESEXB_IGNORE_LINE_OF_SIGHT) && !(getSpellInfo()->getAttributesExE() & ATTRIBUTESEXE_SKIP_LINE_OF_SIGHT_CHECK) &&
2011 (m_caster->GetMapId() != target->GetMapId() || !m_caster->IsWithinLOSInMap(target)))
2013 }
2014
2015 if (target->isPlayer())
2016 {
2017 // Check if target is dueling
2018 // but allow spell cast if target is unfriendly
2019 const auto targetPlayer = dynamic_cast<Player*>(target);
2020 if (targetPlayer->getDuelState() == DUEL_STATE_STARTED)
2021 {
2022 if (auto* const playerOwner = getCaster()->getPlayerOwnerOrSelf())
2023 {
2024 if (targetPlayer->getDuelPlayer() != playerOwner && playerOwner->isFriendlyTo(targetPlayer))
2026 }
2027 }
2028
2029 // Check if caster or target is in a sanctuary area
2030 // but allow spell casting in duels
2031 if (auto* const playerOwner = getCaster()->getPlayerOwnerOrSelf())
2032 {
2033 if (targetPlayer->getDuelPlayer() != playerOwner && !playerOwner->isFriendlyTo(targetPlayer))
2034 {
2036 (targetPlayer->GetArea() != nullptr && targetPlayer->GetArea()->flags & MapManagement::AreaManagement::AREA_SANCTUARY))
2038 }
2039 }
2040
2041 // Do not allow spell casts on players when they are on a taxi
2042 // unless it's a summoning spell
2043 if (targetPlayer->isOnTaxi() && !getSpellInfo()->hasEffect(SPELL_EFFECT_SUMMON_PLAYER))
2045 }
2047 {
2048 // Check only single target spells here
2049 // Spell target system handles this for area spells
2050 if (!(explicitTargetMask & SPELL_TARGET_AREA_MASK))
2052 }
2053
2054 // Check if target has stronger aura active
2055 const AuraCheckResponse auraCheckResponse = target->auraCheck(getSpellInfo(), m_caster);
2056 if (auraCheckResponse.Error == AURA_CHECK_RESULT_HIGHER_BUFF_PRESENT)
2058
2059 // Check if target is immune to this dispel type
2060 //\ TODO: fix me (move to DidHit?) -Appled
2061 if (target->m_dispels[getSpellInfo()->getDispelType()])
2062 return SPELL_FAILED_IMMUNE;
2063 }
2064 }
2065
2066 if (p_caster != nullptr)
2067 {
2068 // Check if spell requires a dead pet
2070 {
2071 const auto pet = p_caster->getPet();
2072 if (pet != nullptr)
2073 {
2074 if (pet->isAlive())
2076 }
2077 else
2078 {
2079 // Find dead pet from any active slot
2080 auto foundDeadPet = false;
2081 for (const auto& [petSlot, petId] : p_caster->getPetCachedSlotMap())
2082 {
2083 if (petSlot >= PET_SLOT_MAX_ACTIVE_SLOT)
2084 break;
2085
2086 const auto petCache = p_caster->getPetCache(petId);
2087 if (petCache == nullptr)
2088 continue;
2089
2090 if (!petCache->alive)
2091 {
2092 foundDeadPet = true;
2093 // Save pet id for later use
2094 add_damage = petCache->number;
2095 break;
2096 }
2097 }
2098
2099 // todo: probably not correct error message
2100 if (!foundDeadPet)
2102 }
2103 }
2104
2105 // Check if spell effect requires pet target
2106 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
2107 {
2108 if (getSpellInfo()->getEffectImplicitTargetA(i) == EFF_TARGET_PET)
2109 {
2110 const auto pet = p_caster->getPet();
2111 if (pet == nullptr)
2113 else if (!pet->isAlive())
2115 // Check Line of Sight with pets as well
2116 if (!m_triggeredSpell && worldConfig.terrainCollision.isCollisionEnabled)
2117 {
2118 if (m_caster->IsInWorld() && !(getSpellInfo()->getAttributesExB() & ATTRIBUTESEXB_IGNORE_LINE_OF_SIGHT) && !(getSpellInfo()->getAttributesExE() & ATTRIBUTESEXE_SKIP_LINE_OF_SIGHT_CHECK) &&
2119 (m_caster->GetMapId() != pet->GetMapId() || !m_caster->IsWithinLOSInMap(pet)))
2121 }
2122 }
2123 }
2124 }
2125
2126 ////////////////////////////////////////////////////////
2127 // Area checks
2128
2129 // Check Line of Sight for spells with a destination
2130 if (m_targets.hasDestination() && !m_triggeredSpell && worldConfig.terrainCollision.isCollisionEnabled)
2131 {
2132 if (m_caster->IsInWorld() && !(getSpellInfo()->getAttributesExB() & ATTRIBUTESEXB_IGNORE_LINE_OF_SIGHT) && !(getSpellInfo()->getAttributesExE() & ATTRIBUTESEXE_SKIP_LINE_OF_SIGHT_CHECK) &&
2135 }
2136
2137 if (p_caster != nullptr)
2138 {
2139 // Check if spell requires certain area
2140 if (getSpellInfo()->getRequiresAreaId() > 0)
2141 {
2142 auto areaEntry = p_caster->GetArea();
2143 if (areaEntry == nullptr)
2145 if (areaEntry == nullptr)
2146 return SPELL_FAILED_NOT_HERE;
2147
2148 const auto requireAreaId = static_cast<uint32_t>(getSpellInfo()->getRequiresAreaId());
2149#if VERSION_STRING == TBC
2150 if (requireAreaId != areaEntry->id && requireAreaId != areaEntry->zone)
2151 {
2152 *parameter1 = getSpellInfo()->getRequiresAreaId();
2154 }
2155#elif VERSION_STRING >= WotLK
2156 auto found = false;
2157 auto areaGroup = sAreaGroupStore.lookupEntry(requireAreaId);
2158 while (areaGroup != nullptr)
2159 {
2160 for (const auto& i : areaGroup->AreaId)
2161 {
2162 if (i == areaEntry->id || (areaEntry->zone != 0 && i == areaEntry->zone))
2163 {
2164 found = true;
2165 *parameter1 = 0;
2166 break;
2167 }
2168 else if (i != 0)
2169 {
2170 *parameter1 = i;
2171 }
2172 }
2173
2174 if (found || areaGroup->next_group == 0)
2175 break;
2176
2177 areaGroup = sAreaGroupStore.lookupEntry(areaGroup->next_group);
2178 }
2179
2180 if (!found)
2182#endif
2183 }
2184
2185 // Flying mount check
2186 if (getSpellInfo()->getAttributesExD() & ATTRIBUTESEXD_ONLY_IN_OUTLANDS)
2187 {
2189 {
2190 if (p_caster->GetMapId() != 571 || !(getSpellInfo()->getAttributesExG() & ATTRIBUTESEXG_IGNORE_COLD_WEATHER_FLYING))
2191 return SPELL_FAILED_NOT_HERE;
2192 }
2193 }
2194
2195 // Check if spell can be casted while mounted or on a taxi
2196 // but skip triggered and passive spells
2198 {
2199 if (p_caster->isOnTaxi())
2200 {
2202 }
2203 else
2204 {
2205 if (!(getSpellInfo()->getAttributes() & ATTRIBUTES_MOUNT_CASTABLE))
2207 }
2208 }
2209
2210 // Check if spell can be casted in heroic dungeons or in raids
2212 {
2214 {
2215#if VERSION_STRING < WotLK
2216 return SPELL_FAILED_NOT_HERE;
2217#else
2218 return SPELL_FAILED_NOT_IN_RAID_INSTANCE;
2219#endif
2220 }
2221 }
2222 }
2223
2224 ////////////////////////////////////////////////////////
2225 // Item, state, range and power checks
2226
2227 const SpellCastResult itemCastResult = checkItems(parameter1, parameter2);
2228 if (itemCastResult != SPELL_CAST_SUCCESS)
2229 return itemCastResult;
2230
2231 if (!m_triggeredSpell)
2232 {
2233 const SpellCastResult casterStateResult = checkCasterState();
2234 if (casterStateResult != SPELL_CAST_SUCCESS)
2235 return casterStateResult;
2236
2237 const SpellCastResult rangeResult = checkRange(secondCheck);
2238 if (rangeResult != SPELL_CAST_SUCCESS)
2239 return rangeResult;
2240
2241 const SpellCastResult powerResult = checkPower();
2242 if (powerResult != SPELL_CAST_SUCCESS)
2243 return powerResult;
2244 }
2245
2246 ////////////////////////////////////////////////////////
2247 // Spell focus object check
2248
2249 if (p_caster != nullptr && getSpellInfo()->getRequiresSpellFocus() > 0)
2250 {
2251 auto found = false;
2252 for (const auto& itr : p_caster->getInRangeObjectsSet())
2253 {
2254 if (itr == nullptr || !itr->isGameObject())
2255 continue;
2256
2257 if (const auto obj = dynamic_cast<GameObject*>(itr))
2258 {
2259 if (obj->getGoType() != GAMEOBJECT_TYPE_SPELL_FOCUS)
2260 continue;
2261
2262 // Skip objects from other phases
2263 if (!(p_caster->GetPhase() & obj->GetPhase()))
2264 continue;
2265
2266 const auto gameObjectInfo = obj->GetGameObjectProperties();
2267 if (gameObjectInfo == nullptr)
2268 {
2269 sLogger.debugFlag(AscEmu::Logging::LF_SPELL, "Spell::canCast : Found gameobject entry {} with invalid gameobject properties, spawn id {}", obj->getEntry(), obj->getGuidLow());
2270 continue;
2271 }
2272
2273 // Prefer to use range from gameobject_properties instead of spell's range
2274 // That is required at least for profession spells since their range is set to 0 yards in DBC files
2275 float_t distance = 0.0f;
2276 if (gameObjectInfo->spell_focus.distance > 0)
2277 {
2278 // Database seems to already have squared distances
2279 distance = static_cast<float_t>(gameObjectInfo->spell_focus.distance);
2280 }
2281 else
2282 {
2283 distance = getSpellInfo()->getMaxRange(false, p_caster, this);
2284 distance *= distance;
2285 }
2286
2287 // Skip objects which are out of range
2288 if (!p_caster->isInRange(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), distance))
2289 continue;
2290
2291 if (gameObjectInfo->spell_focus.focus_id == getSpellInfo()->getRequiresSpellFocus())
2292 {
2293 found = true;
2294 break;
2295 }
2296 }
2297 }
2298
2299 if (!found)
2300 {
2301 *parameter1 = getSpellInfo()->getRequiresSpellFocus();
2303 }
2304 }
2305
2306 ////////////////////////////////////////////////////////
2307 // Spell target constraint check (checks if spell is castable only on certain creature or gameobject)
2308
2309 if (m_targetConstraint != nullptr)
2310 {
2311 // Search for target constraint from within spell's max range
2312 float_t range = 0.0f;
2313 const auto rangeEntry = sSpellRangeStore.lookupEntry(getSpellInfo()->getRangeIndex());
2314 if (rangeEntry != nullptr)
2315 range = rangeEntry->maxRange;
2316
2317 auto foundTarget = false;
2318
2319 // Check if target needs to be a certain creature
2320 for (const auto& entryId : m_targetConstraint->getCreatures())
2321 {
2323 {
2324 // Spell requires an implicit target
2325 // Find closest creature with the required entry id
2326 const auto creatureTarget = m_caster->IsInWorld() ? m_caster->getWorldMap()->getInterface()->getCreatureNearestCoords(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), entryId) : nullptr;
2327 if (creatureTarget != nullptr)
2328 {
2329 // Check that the creature is within spell's range
2330 if (m_caster->isInRange(creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(), range * range))
2331 {
2332 setTargetConstraintCreature(creatureTarget);
2333 foundTarget = true;
2334 break;
2335 }
2336 }
2337 }
2338 else
2339 {
2340 // Spell requires an explicit target
2341 // Most these spells are casted from items and then client does NOT send target guid in cast spell packet
2342 Unit* creatureTarget = nullptr;
2343 if (p_caster != nullptr)
2344 {
2345 // If caster is player, use player's selected target
2346 creatureTarget = p_caster->getWorldMapUnit(p_caster->getTargetGuid());
2347 }
2348 else if (u_caster != nullptr)
2349 {
2350 // If caster is creature, use the one set in castSpell function
2352 if (creatureTarget == nullptr)
2353 creatureTarget = u_caster->getWorldMapUnit(u_caster->getTargetGuid());
2354 }
2355
2356 if (creatureTarget == nullptr)
2357 continue;
2358
2359 if (!creatureTarget->isCreature() || creatureTarget->getEntry() != entryId)
2361
2362 // Check that the creature is within spell's range
2363 if (!m_caster->isInRange(creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(), range * range))
2365
2366 // Found target
2367 setTargetConstraintCreature(dynamic_cast<Creature*>(creatureTarget));
2368 foundTarget = true;
2369 break;
2370 }
2371 }
2372
2373 // Check if target needs to be a certain gameobject
2374 for (const auto& entryId : m_targetConstraint->getGameObjects())
2375 {
2377 {
2378 // Spell requires an implicit target
2379 // Find closest gameobject with the required entry id
2381 if (gobTarget != nullptr)
2382 {
2383 // Check that the gameobject is within spell's range
2384 if (m_caster->isInRange(gobTarget->GetPositionX(), gobTarget->GetPositionY(), gobTarget->GetPositionZ(), range * range))
2385 {
2387 foundTarget = true;
2388 }
2389 }
2390 }
2391 else
2392 {
2393 // Spell requires an explicit target
2394 const auto objectTarget = m_caster->getWorldMapObject(m_targets.getGameObjectTargetGuid());
2395 if (objectTarget == nullptr)
2396 continue;
2397
2398 if (!objectTarget->isGameObject() || objectTarget->getEntry() != entryId)
2400
2401 // Check that the gameobject is within the spell's range
2402 if (!m_caster->isInRange(objectTarget->GetPositionX(), objectTarget->GetPositionY(), objectTarget->GetPositionZ(), range * range))
2404
2405 // Found target
2406 setTargetConstraintGameObject(dynamic_cast<GameObject*>(objectTarget));
2407 foundTarget = true;
2408 break;
2409 }
2410 }
2411
2412 if (!foundTarget)
2414 }
2415
2416 ////////////////////////////////////////////////////////
2417 // Check for scripted cast check
2418
2419 const SpellCastResult scriptCheck = sScriptMgr.callScriptedSpellCanCast(this, parameter1, parameter2);
2420 if (scriptCheck != SPELL_CAST_SUCCESS)
2421 return scriptCheck;
2422
2423 ////////////////////////////////////////////////////////
2424 // Special checks for different spell effects
2425
2426 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
2427 {
2428 switch (getSpellInfo()->getEffect(i))
2429 {
2432 {
2433 if (target == nullptr)
2435 if (target->isAlive())
2437#if VERSION_STRING >= WotLK
2438 if (target->hasAuraWithAuraEffect(SPELL_AURA_PREVENT_RESURRECTION))
2439 return SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED;
2440#endif
2441 } break;
2444 {
2445 if (u_caster == nullptr)
2446 break;
2447
2448 if (u_caster->getPet() != nullptr && !(getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_DISMISS_CURRENT_PET))
2449 {
2450 if (getSpellInfo()->getEffect(i) == SPELL_EFFECT_SUMMON)
2451 {
2452 // Check from summon properties if this new pet is actually a pet
2453 if (const auto summonProperties = sSummonPropertiesStore.lookupEntry(getSpellInfo()->getEffectMiscValueB(i)))
2454 {
2455 if (summonProperties->ControlType == SUMMON_CONTROL_TYPE_PET || summonProperties->Type == SUMMONTYPE_PET)
2457 }
2458 }
2459 else
2460 {
2462 }
2463 }
2464
2465 if (u_caster->getCharmGuid() != 0)
2467 } break;
2468 case SPELL_EFFECT_LEAP:
2470 {
2471 if (p_caster == nullptr)
2472 break;
2473
2474 // Don't allow these effects in battlegrounds if the battleground hasn't yet started
2477 } break;
2480 {
2481 if (p_caster == nullptr)
2482 break;
2483
2484 uint32_t lockId = 0;
2486 {
2488 if (objectTarget != nullptr &&
2489 objectTarget->getGoType() != GAMEOBJECT_TYPE_QUESTGIVER &&
2490 objectTarget->getGoType() != GAMEOBJECT_TYPE_AREADAMAGE &&
2491 objectTarget->getGoType() != GAMEOBJECT_TYPE_FLAGSTAND &&
2492 objectTarget->getGoType() != GAMEOBJECT_TYPE_FLAGDROP)
2493 {
2494 // Get lock id
2495 switch (objectTarget->getGoType())
2496 {
2498 lockId = objectTarget->GetGameObjectProperties()->door.lock_id;
2499 break;
2501 lockId = objectTarget->GetGameObjectProperties()->button.lock_id;
2502 break;
2503 // TODO: implement questgiver gameobjects
2504 //case GAMEOBJECT_TYPE_QUESTGIVER:
2506 lockId = objectTarget->GetGameObjectProperties()->chest.lock_id;
2507 break;
2509 lockId = objectTarget->GetGameObjectProperties()->trap.lock_id;
2510 break;
2512 lockId = objectTarget->GetGameObjectProperties()->goober.lock_id;
2513 break;
2514 // TODO: implement areadamage gameobjects
2515 //case GAMEOBJECT_TYPE_AREADAMAGE:
2517 lockId = objectTarget->GetGameObjectProperties()->camera.lock_id;
2518 break;
2519 // TODO: implement flagstand gameobjects
2520 //case GAMEOBJECT_TYPE_FLAGSTAND:
2522 lockId = objectTarget->GetGameObjectProperties()->fishinghole.lock_id;
2523 break;
2524 // TODO: implement flagdrop gameobjects
2525 //case GAMEOBJECT_TYPE_FLAGDROP:
2526 default:
2527 break;
2528 }
2529
2530 if (lockId == 0)
2532 }
2533 }
2534 else if (m_targets.getItemTargetGuid() != 0)
2535 {
2536 Item const* targetItem = nullptr;
2537 if (m_targets.isTradeItem())
2538 {
2539 const auto playerTrader = p_caster->getTradeTarget();
2540 if (playerTrader != nullptr)
2541 targetItem = playerTrader->getTradeData()->getTradeItem(TradeSlots(m_targets.getItemTargetGuid()));
2542 }
2543 else
2544 {
2546 }
2547
2548 if (targetItem == nullptr)
2550
2551 // Check if item is already unlocked
2552 if (targetItem->getItemProperties()->LockId == 0 || !targetItem->m_isLocked)
2554
2555 lockId = targetItem->getItemProperties()->LockId;
2556 }
2557
2558 if (lockId == 0)
2559 break;
2560
2561 const auto lockInfo = sLockStore.lookupEntry(lockId);
2562 if (lockInfo == nullptr)
2564
2565 auto successfulOpening = false;
2566 for (uint8_t x = 0; x < LOCK_NUM_CASES; ++x)
2567 {
2568 // Check if object requires an item for unlocking
2569 if (lockInfo->locktype[x] == LOCK_KEY_ITEM)
2570 {
2571 if (i_caster == nullptr || lockInfo->lockmisc[x] == 0)
2572 continue;
2573 // No need to check further on a successful match
2574 if (i_caster->getEntry() == lockInfo->lockmisc[x])
2575 {
2576 successfulOpening = true;
2577 break;
2578 }
2579 }
2580 // Check if object requires a skill for unlocking
2581 else if (lockInfo->locktype[x] == LOCK_KEY_SKILL)
2582 {
2583 // Check if spell's skill matches with the required skill
2584 if (static_cast<uint32_t>(getSpellInfo()->getEffectMiscValue(i)) != lockInfo->lockmisc[x])
2585 continue;
2586
2587 // Get required skill line
2588 uint16_t skillId = 0;
2589 switch (lockInfo->lockmisc[x])
2590 {
2591#if VERSION_STRING <= WotLK
2592 case LOCKTYPE_PICKLOCK:
2593 skillId = SKILL_LOCKPICKING;
2594 break;
2595#endif
2596 case LOCKTYPE_HERBALISM:
2597 skillId = SKILL_HERBALISM;
2598 break;
2599 case LOCKTYPE_MINING:
2600 skillId = SKILL_MINING;
2601 break;
2602 case LOCKTYPE_FISHING:
2603 skillId = SKILL_FISHING;
2604 break;
2605#if VERSION_STRING >= WotLK
2607 skillId = SKILL_INSCRIPTION;
2608 break;
2609#endif
2610 default:
2611 break;
2612 }
2613
2614 if (skillId != 0 || lockInfo->lockmisc[x] == LOCKTYPE_BLASTING)
2615 {
2616 // If item is used for opening, do not use player's skill level
2617 uint32_t skillLevel = i_caster != nullptr || p_caster == nullptr ? 0 : p_caster->getSkillLineCurrent(skillId);
2618 // Add skill bonuses from the spell
2619 skillLevel += getSpellInfo()->calculateEffectValue(i);;
2620
2621 // Check for low skill level
2622 if (skillLevel < lockInfo->minlockskill[x])
2624
2625#if VERSION_STRING >= WotLK
2626 // Patch 3.2.0: In addition to the normal requirements, mining deposits in Northrend now require a minimum character level of 65 to mine.
2627 if (p_caster)
2628 {
2629 if (skillId == SKILL_MINING && p_caster->GetMapId() == 571 && p_caster->getLevel() < 65)
2630 {
2632 return SPELL_FAILED_CUSTOM_ERROR;
2633 }
2634 }
2635#endif
2636
2637#if VERSION_STRING < Cata
2638 // Check for failed attempt only at the end of cast
2639 // Patch 3.1.0: You can no longer fail when Mining, Herbing, and Skinning
2640 if (secondCheck && (skillId == SKILL_LOCKPICKING
2641#if VERSION_STRING < WotLK
2642 || skillId == SKILL_HERBALISM || skillId == SKILL_MINING
2643#endif
2644 ))
2645 {
2646 // Failed attempt can only happen at orange gather/pick lock and can also happen at max skill level
2647 // In gathering professions orange most of the time turns to green after gaining 25 skill points
2648 const auto skillDifference = skillLevel - lockInfo->minlockskill[x];
2649 uint8_t failChance = 0;
2650 // TODO: these values are some what correct for Classic but not confirmed
2651 // need more research for TBC -Appled
2652 if (skillDifference < 5)
2653 failChance = 50;
2654 else if (skillDifference < 10)
2655 failChance = 35;
2656 else if (skillDifference < 15)
2657 failChance = 20;
2658 else if (skillDifference < 20)
2659 failChance = 10;
2660 else if (skillDifference < 25)
2661 failChance = 5;
2662
2663 if (failChance > 0 && Util::getRandomUInt(100) < failChance)
2665 }
2666#endif
2667 }
2668
2669 successfulOpening = true;
2670 break;
2671 }
2672 }
2673
2674 if (!successfulOpening)
2676 } break;
2678 {
2679 if (getSpellInfo()->getEffectImplicitTargetA(i) != EFF_TARGET_PET)
2680 break;
2681 }
2682 [[fallthrough]];
2684 {
2685 if (p_caster == nullptr)
2686 break;
2687
2688 const auto pet = p_caster->getPet();
2689 if (pet == nullptr)
2690 return SPELL_FAILED_NO_PET;
2691
2692 const auto newSpell = sSpellMgr.getSpellInfo(getSpellInfo()->getEffectTriggerSpell(i));
2693 if (newSpell == nullptr)
2695
2696 const auto learnStatus = pet->canLearnSpell(newSpell);
2697 if (learnStatus != SPELL_CAST_SUCCESS)
2698 return learnStatus;
2699 } break;
2702 {
2703 if (u_caster == nullptr)
2704 break;
2705
2706 if (target == nullptr)
2708
2709 // Do not check further for self casts
2710 if (u_caster == target)
2711 break;
2712
2713 // Check for correct power type
2714 if (target->getMaxPower(target->getPowerType()) == 0 || target->getPowerType() != static_cast<uint8_t>(getSpellInfo()->getEffectMiscValue(i)))
2716 } break;
2718 {
2719 if (p_caster == nullptr)
2721
2722 if (!target->isCreature())
2724
2725 // Check if target is already pick pocketed
2726 if (dynamic_cast<Creature*>(target)->IsPickPocketed())
2728
2729 const auto itr = sLootMgr.getPickpocketingLoot().find(target->getEntry());
2730 if (itr == sLootMgr.getPickpocketingLoot().end())
2732 } break;
2733#if VERSION_STRING >= WotLK
2735 {
2736 if (p_caster == nullptr)
2738
2739 const auto glyphId = static_cast<uint32_t>(getSpellInfo()->getEffectMiscValue(i));
2740 const auto glyphEntry = sGlyphPropertiesStore.lookupEntry(glyphId);
2741 if (glyphEntry == nullptr)
2742 return SPELL_FAILED_INVALID_GLYPH;
2743
2744 // Check if glyph slot is locked
2745 if (!(p_caster->getGlyphsEnabled() & (1 << m_glyphslot)))
2746 return SPELL_FAILED_GLYPH_SOCKET_LOCKED;
2747
2748 // Check if player already has this glyph
2749 if (p_caster->hasAurasWithId(glyphEntry->SpellID))
2750 return SPELL_FAILED_UNIQUE_GLYPH;
2751 } break;
2752#endif
2753 case SPELL_EFFECT_DUEL:
2754 {
2755 if (p_caster == nullptr)
2756 break;
2757
2760
2761 if (p_caster->isStealthed())
2763
2764 if (p_caster->isInvisible())
2766
2767 // Check if caster is in dungeon or raid
2770
2771 const auto targetPlayer = p_caster->getWorldMapPlayer(m_targets.getUnitTargetGuid());
2772 if (targetPlayer != nullptr && targetPlayer->GetTransport() != p_caster->GetTransport())
2774
2775 if (targetPlayer != nullptr && targetPlayer->getDuelPlayer() != nullptr)
2777 } break;
2779 {
2780 if (p_caster == nullptr || target == nullptr || !target->isPlayer())
2782
2783 const auto targetPlayer = dynamic_cast<Player*>(target);
2784 // Check if target is in same group/raid with the caster
2785 if (targetPlayer == p_caster || p_caster->getGroup() == nullptr || !p_caster->getGroup()->HasMember(targetPlayer))
2787
2788 // Check if caster is in an instance map
2790 {
2791 if (!p_caster->IsInMap(targetPlayer))
2793
2794 const auto mapInfo = p_caster->getWorldMap()->getBaseMap()->getMapInfo();
2796 {
2797 if (mapInfo->minlevel_heroic > targetPlayer->getLevel())
2798 return SPELL_FAILED_LOWLEVEL;
2799 }
2800 else
2801 {
2802 if (mapInfo->minlevel > targetPlayer->getLevel())
2803 return SPELL_FAILED_LOWLEVEL;
2804 }
2805
2806 // Check if caster is in a battleground
2808 {
2809#if VERSION_STRING == Classic
2810 return SPELL_FAILED_NOT_HERE;
2811#else
2812 return SPELL_FAILED_NOT_IN_BATTLEGROUND;
2813#endif
2814 }
2815 }
2816 } break;
2818 {
2819#if VERSION_STRING >= WotLK
2821 return SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED;
2822#endif
2823 } break;
2825 {
2826 if (p_caster == nullptr)
2828
2829 if (target == nullptr)
2831
2832 if (target->isAlive())
2834
2835 if (!target->hasUnitFlags(UNIT_FLAG_SKINNABLE) || !target->isCreature())
2837
2838 // Check if creature is already skinned
2839 const auto creatureTarget = dynamic_cast<Creature*>(target);
2840 if (creatureTarget->Skinned)
2842
2843 // Check if creature is looted
2844 if (creatureTarget->loot.isLooted() && creatureTarget->isTagged())
2845 {
2846 const auto taggerPlayer = creatureTarget->getWorldMapPlayer(creatureTarget->getTaggerGuid());
2847 if (taggerPlayer != nullptr && creatureTarget->HasLootForPlayer(taggerPlayer))
2849 }
2850
2851 // Check if caster has required skinning level for target
2852 const auto skillLevel = p_caster->getSkillLineCurrent(creatureTarget->GetRequiredLootSkill());
2853 // Required skinning level is calculated by multiplying the target's level by 5
2854 // but if player's skill level is below 100, then player's skill level is incremented by 100 and target's level is multiplied by 10
2855 const int32_t skillDiff = skillLevel >= 100 ? skillLevel - (creatureTarget->getLevel() * 5) : (skillLevel + 100) - (creatureTarget->getLevel() * 10);
2856 if (skillDiff < 0)
2858
2859#if VERSION_STRING < WotLK
2860 // Check for failed attempt at the end of cast
2861 // Patch 3.1.0: You can no longer fail when Mining, Herbing, and Skinning
2862 if (secondCheck)
2863 {
2864 uint8_t failChance = 0;
2865 // TODO: these values are some what correct for Classic but not confirmed
2866 // need more research for TBC -Appled
2867 if (skillDiff < 5)
2868 failChance = 50;
2869 else if (skillDiff < 10)
2870 failChance = 35;
2871 else if (skillDiff < 15)
2872 failChance = 20;
2873 else if (skillDiff < 20)
2874 failChance = 10;
2875 else if (skillDiff < 25)
2876 failChance = 5;
2877
2878 if (failChance > 0 && Util::getRandomUInt(100) < failChance)
2880 }
2881#endif
2882 } break;
2884 {
2885 if (u_caster == nullptr)
2887
2888 if (u_caster->isRooted())
2889 return SPELL_FAILED_ROOTED;
2890
2891 if (target == nullptr)
2893
2894 if (worldConfig.terrainCollision.isPathfindingEnabled)
2895 {
2896 // Check if caster is able to create path to target
2897 if (!u_caster->getAIInterface()->canCreatePath(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()))
2898 return SPELL_FAILED_NOPATH;
2899 }
2900 } break;
2902 {
2903 if (p_caster == nullptr)
2905
2906 const auto pet = p_caster->getPet();
2907 if (pet == nullptr)
2908 return SPELL_FAILED_NO_PET;
2909
2910 if (!pet->isAlive())
2912
2913 // Get the food
2915 if (foodItem == nullptr)
2917
2918 // Check if the item is food
2919 const auto itemProto = foodItem->getItemProperties();
2920 if (itemProto->FoodType == 0)
2922
2923 // Check if the food type matches pet's diet
2924 if (!(pet->getPetDiet() & (1 << (itemProto->FoodType - 1))))
2926
2927 // Check if the food level is at most 30 levels below pet's level
2928 if (pet->getLevel() > (itemProto->ItemLevel + 30))
2930 } break;
2932 {
2933 if (p_caster == nullptr)
2934 return SPELL_FAILED_NO_PET;
2935
2936 // Spells with this attribute were checked already
2937 if (!(getSpellInfo()->getAttributesExB() & ATTRIBUTESEXB_REQ_DEAD_PET))
2938 {
2939 const auto petTarget = p_caster->getPet();
2940 if (petTarget != nullptr)
2941 {
2942 if (petTarget->isAlive())
2944 }
2945 else
2946 {
2947 // Find dead pet from any active slot
2948 auto foundDeadPet = false;
2949 for (const auto& [petSlot, petId] : p_caster->getPetCachedSlotMap())
2950 {
2951 if (petSlot >= PET_SLOT_MAX_ACTIVE_SLOT)
2952 break;
2953
2954 const auto petCache = p_caster->getPetCache(petId);
2955 if (petCache == nullptr)
2956 continue;
2957
2958 if (!petCache->alive)
2959 {
2960 foundDeadPet = true;
2961 // Save pet id for later use
2962 add_damage = petCache->number;
2963 break;
2964 }
2965 }
2966
2967 // todo: probably not correct error message
2968 if (!foundDeadPet)
2970 }
2971 }
2972 } break;
2974 {
2977 } break;
2978 default:
2979 break;
2980 }
2981 }
2982
2983 ////////////////////////////////////////////////////////
2984 // Special checks for different aura effects
2985
2986 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
2987 {
2988 switch (getSpellInfo()->getEffectApplyAuraName(i))
2989 {
2991 {
2992 if (p_caster == nullptr)
2994
2995 if (target == nullptr)
2997
2998 if (target == p_caster)
3000
3001 if (p_caster->getPet() != nullptr && !(getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_DISMISS_CURRENT_PET))
3003
3004 if (p_caster->getCharmGuid() != 0)
3006
3007 // Check if caster is charmed
3008 if (p_caster->getCharmedByGuid() != 0)
3009 return SPELL_FAILED_CHARMED;
3010
3011 // Check if target is already charmed
3012 if (target->getCharmedByGuid() != 0)
3014
3015 // Check if target is owned by player
3016 if (!target->isPlayer() && target->getPlayerOwner() != nullptr)
3017 {
3018#if VERSION_STRING == Classic
3020#else
3021 return SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED;
3022#endif
3023 }
3024
3025 if (static_cast<int32_t>(target->getLevel()) > calculateEffect(i))
3027 } break;
3030 {
3031 if (u_caster == nullptr)
3033
3034 if (target == nullptr)
3036
3037 if (target == u_caster)
3039
3040 if (getSpellInfo()->getEffectApplyAuraName(i) == SPELL_AURA_MOD_CHARM)
3041 {
3042 if (p_caster != nullptr && p_caster->getPet() != nullptr && !(getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_DISMISS_CURRENT_PET))
3044
3045 // Player can have only one charm at time
3046 if (p_caster != nullptr && p_caster->getCharmGuid() != 0)
3048 }
3049
3050 // Check if caster is charmed
3051 if (u_caster->getCharmedByGuid() != 0)
3052 return SPELL_FAILED_CHARMED;
3053
3054 // Check if target is already charmed
3055 if (target->getCharmedByGuid() != 0)
3057
3058 // Check if target is owned by player
3059 if (!target->isPlayer() && target->getPlayerOwner() != nullptr)
3060 {
3061#if VERSION_STRING == Classic
3063#else
3064 return SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED;
3065#endif
3066 }
3067
3068 if (static_cast<int32_t>(target->getLevel()) > calculateEffect(i))
3070
3071 const auto targetCreature = dynamic_cast<Creature*>(target);
3072 if (p_caster != nullptr && target->isCreature() && targetCreature->isTagged() && !targetCreature->isTaggedByPlayerOrItsGroup(p_caster))
3074 } break;
3076 {
3077 // Skip for non-player and item casters
3078 if (p_caster == nullptr || i_caster != nullptr)
3079 break;
3080
3081 if (target != nullptr && (target->getMaxPower(POWER_TYPE_MANA) == 0 || target->getPowerType() != POWER_TYPE_MANA))
3083 } break;
3085 {
3086 if (target == nullptr)
3088
3089 // Check if target is not already disarmed
3090 if (target->getUnitFlags() & UNIT_FLAG_DISARMED)
3092
3093 if (target->isPlayer())
3094 {
3095 // Check if player is even wielding a weapon
3096 const auto mainHandWeapon = dynamic_cast<Player*>(target)->getItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND);
3097 if (mainHandWeapon == nullptr || !mainHandWeapon->isWeapon())
3099 }
3100 else
3101 {
3102 if (const auto creature = dynamic_cast<Creature*>(target))
3103 {
3104 if (const auto creatureProto = creature->GetCreatureProperties())
3105 {
3106 if (creatureProto->Type != UNIT_TYPE_HUMANOID && creatureProto->Type != UNIT_TYPE_DEMON &&
3107 creatureProto->Type != UNIT_TYPE_GIANT && creatureProto->Type != UNIT_TYPE_UNDEAD)
3109 }
3110 }
3111
3112 // Check if creature is even wielding a weapon
3113#if VERSION_STRING < WotLK
3114 if (target->getVirtualItemDisplayId(MELEE) == 0)
3115#else
3116 if (target->getVirtualItemSlotId(MELEE) == 0)
3117#endif
3119 }
3120 } break;
3121 case SPELL_AURA_MOUNTED:
3122 {
3123 if (worldConfig.terrainCollision.isCollisionEnabled)
3124 {
3127 }
3128
3129 if (p_caster != nullptr)
3130 {
3131#if VERSION_STRING == Cata
3133 return SPELL_FAILED_NOT_HERE;
3134#endif
3135
3136 if (p_caster->GetTransport() != nullptr)
3138
3140 {
3143 }
3144
3145 // Check shapeshift form
3147 {
3148 switch (p_caster->getShapeShiftForm())
3149 {
3150 case FORM_CAT:
3151 case FORM_TREE:
3152 case FORM_TRAVEL:
3153 case FORM_AQUA:
3154 case FORM_BEAR:
3155 case FORM_GHOUL:
3156 case FORM_DIREBEAR:
3157 case FORM_CREATUREBEAR:
3158 case FORM_CREATURECAT:
3159 case FORM_GHOSTWOLF:
3160 case FORM_ZOMBIE:
3161 case FORM_METAMORPHOSIS:
3162 case FORM_DEMON:
3163 case FORM_FLIGHT:
3164 case FORM_MOONKIN:
3166 {
3169 } break;
3170 default:
3171 break;
3172 }
3173 }
3174 }
3175 } break;
3177 {
3178 if (p_caster == nullptr)
3180
3181 if (p_caster->getCharmGuid() != 0)
3183
3184 if (p_caster->getCharmedByGuid() != 0)
3185 return SPELL_FAILED_CHARMED;
3186
3187 const auto petTarget = p_caster->getPet();
3188 if (petTarget == nullptr)
3189 return SPELL_FAILED_NO_PET;
3190
3191 if (petTarget->getCharmedByGuid() != 0)
3193 } break;
3194#if VERSION_STRING >= TBC
3195 case SPELL_AURA_FLY:
3197 {
3198 if (p_caster != nullptr && p_caster->isAlive())
3199 {
3202 }
3203 } break;
3205 {
3206 // Clone effects require creature or player target
3207 if (target == nullptr)
3209
3210 if (target->getGuid() == m_caster->getGuid())
3212
3213 // Cloned targets cannot be cloned
3214 if (target->hasAuraWithAuraEffect(SPELL_AURA_MIRROR_IMAGE))
3216 } break;
3217#endif
3218 default:
3219 break;
3220 }
3221 }
3222
3223 if (m_targets.isTradeItem())
3224 {
3225 if (p_caster == nullptr)
3227
3228 // Slot must be the lowest
3231
3232 // Check if player is even trading
3233 if (p_caster->getTradeData() == nullptr)
3235
3236 // Cast the trade spell only when both parties have accepted the trade
3237 const auto tradeData = p_caster->getTradeData();
3238 if (!tradeData->isTradeAccepted() || !tradeData->getTargetTradeData()->isTradeAccepted())
3239 {
3240 // If either one hasn't accepted the trade, save the spell and cast it on trade complete
3241 tradeData->setTradeSpell(getSpellInfo()->getId(), i_caster);
3243 }
3244 }
3245
3246 // Call legacy CanCast for yet unhandled cases
3247 return m_triggeredSpell || ProcedOnSpell != nullptr ? SPELL_CAST_SUCCESS : SpellCastResult(CanCast(secondCheck));
3248}
@ SPELL_AURA_PREVENT_RESURRECTION
@ SPELL_AURA_MIRROR_IMAGE
@ SPELL_AURA_MOD_DISARM
@ SPELL_AURA_PERIODIC_MANA_LEECH
@ SPELL_AURA_MOD_POSSESS_PET
@ SPELL_AURA_SPIRIT_OF_REDEMPTION
@ SPELL_AURA_FLY
@ SPELL_AURA_GHOST
@ SPELL_AURA_MOD_CHARM
@ SPELL_AURA_AREA_CHARM
@ SPELL_AURA_ALLOW_TAME_PET_TYPE
@ SPELL_AURA_MOUNTED
@ SPELL_AURA_IGNORE_SHAPESHIFT
@ SPELL_AURA_IGNORE_TARGET_AURA_STATE
@ SPELL_AURA_MOD_POSSESS
@ SPELL_AURA_MOD_STEALTH
@ SPELL_AURA_ENABLE_FLIGHT2
@ AURA_INTERRUPT_ON_STAND_UP
AuraState
Definition AuraStates.hpp:9
@ CORPSE_STATE_BONES
Definition Corpse.hpp:16
@ CREATURE_FLAG1_TAMEABLE
@ UNIT_TYPE_BEAST
@ UNIT_TYPE_HUMANOID
@ UNIT_TYPE_UNDEAD
@ UNIT_TYPE_DEMON
@ UNIT_TYPE_GIANT
@ GAMEOBJECT_TYPE_CAMERA
@ GAMEOBJECT_TYPE_BUTTON
@ GAMEOBJECT_TYPE_SPELL_FOCUS
@ GAMEOBJECT_TYPE_TRAP
@ GAMEOBJECT_TYPE_CHEST
@ GAMEOBJECT_TYPE_FISHINGHOLE
@ GAMEOBJECT_TYPE_FLAGDROP
@ GAMEOBJECT_TYPE_QUESTGIVER
@ GAMEOBJECT_TYPE_FLAGSTAND
@ GAMEOBJECT_TYPE_AREADAMAGE
@ GAMEOBJECT_TYPE_GOOBER
@ GAMEOBJECT_TYPE_DOOR
@ EQUIPMENT_SLOT_MAINHAND
@ LOCKTYPE_HERBALISM
Definition LockTypes.hpp:11
@ LOCKTYPE_FISHING
Definition LockTypes.hpp:28
@ LOCKTYPE_BLASTING
Definition LockTypes.hpp:25
@ LOCKTYPE_PICKLOCK
Definition LockTypes.hpp:10
@ LOCKTYPE_MINING
Definition LockTypes.hpp:12
@ LOCKTYPE_INSCRIPTION
Definition LockTypes.hpp:29
@ LOCK_KEY_ITEM
Definition LockTypes.hpp:35
@ LOCK_KEY_SKILL
Definition LockTypes.hpp:36
#define sLootMgr
Definition LootMgr.hpp:106
@ PET_SLOT_MAX_ACTIVE_SLOT
@ PET_SLOT_MAX_TOTAL_PET_COUNT
@ PLAYER_FLAG_GM
@ HUNTER
@ TRADE_SLOT_NONTRADED
@ POWER_TYPE_MANA
Definition PowerType.hpp:13
@ SKILL_INSCRIPTION
Definition Skill.hpp:186
@ SKILL_MINING
Definition Skill.hpp:84
@ SKILL_FISHING
Definition Skill.hpp:128
@ SKILL_LOCKPICKING
Definition Skill.hpp:151
@ SKILL_HERBALISM
Definition Skill.hpp:78
@ TARGET_FLAG_UNIT_CORPSE
@ TARGET_FLAG_CORPSE
@ TARGET_FLAG_CORPSE2
@ ATTRIBUTESEXE_SKIP_LINE_OF_SIGHT_CHECK
@ ATTRIBUTESEXD_NOT_IN_ARENAS
@ ATTRIBUTESEXD_ONLY_IN_OUTLANDS
@ ATTRIBUTESEXG_IS_CHEAT_SPELL
@ ATTRIBUTESEXG_IGNORE_COLD_WEATHER_FLYING
@ ATTRIBUTESEXB_UNAFFECTED_BY_SCHOOL_IMMUNITY
@ ATTRIBUTESEXB_REQ_BEHIND_TARGET
@ ATTRIBUTESEXB_IGNORE_LINE_OF_SIGHT
@ ATTRIBUTESEXB_TAME_BEAST
@ ATTRIBUTESEXB_CANT_TARGET_TAGGED
@ ATTRIBUTESEXB_CAN_BE_CASTED_ON_DEAD_TARGET
@ ATTRIBUTESEXB_REQ_DEAD_PET
@ ATTRIBUTESEXF_CAN_TARGET_INVISIBLE
@ ATTRIBUTESEXF_NOT_IN_RAIDS_OR_HEROIC_DUNGEONS
@ ATTRIBUTESEX_REQ_OOC_TARGET
@ ATTRIBUTESEX_CANT_TARGET_SELF
@ ATTRIBUTESEX_REQ_FACING_TARGET
@ ATTRIBUTESEX_DISMISS_CURRENT_PET
@ ATTRIBUTESEXC_BG_ONLY
@ ATTRIBUTESEXC_TARGET_ONLY_GHOSTS
@ ATTRIBUTES_STOP_ATTACK
\ todo: implement
@ ATTRIBUTES_REQ_OOC
@ ATTRIBUTES_NOT_SHAPESHIFT
@ ATTRIBUTES_MOUNT_CASTABLE
@ ATTRIBUTES_ONLY_INDOORS
@ ATTRIBUTES_REQ_STEALTH
@ ATTRIBUTES_UNK20
@ ATTRIBUTES_CASTABLE_WHILE_SITTING
@ ATTRIBUTES_DEAD_CASTABLE
@ ATTRIBUTES_ONLY_OUTDOORS
@ EFF_TARGET_PET
@ SPELL_EFFECT_LEAP
@ SPELL_EFFECT_POWER_BURN
@ SPELL_EFFECT_SUMMON_PET
@ SPELL_EFFECT_OPEN_LOCK_ITEM
@ SPELL_EFFECT_SELF_RESURRECT
@ SPELL_EFFECT_FEED_PET
@ SPELL_EFFECT_SUMMON_PLAYER
@ SPELL_EFFECT_DUEL
@ SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
@ SPELL_EFFECT_PICKPOCKET
@ SPELL_EFFECT_USE_GLYPH
@ SPELL_EFFECT_RESURRECT_FLAT
@ SPELL_EFFECT_SUMMON
@ SPELL_EFFECT_POWER_DRAIN
@ SPELL_EFFECT_RESURRECT
@ SPELL_EFFECT_CHARGE
@ SPELL_EFFECT_SUMMON_DEAD_PET
@ SPELL_EFFECT_LEARN_SPELL
@ SPELL_EFFECT_SKINNING
@ SPELL_EFFECT_SPELL_STEAL
@ SPELL_EFFECT_OPEN_LOCK
@ SPELL_EFFECT_LEARN_PET_SPELL
SpellCastResult
@ SPELL_FAILED_TARGET_NOT_LOOTED
@ SPELL_FAILED_UNIT_NOT_INFRONT
@ SPELL_FAILED_NOT_INFRONT
@ SPELL_FAILED_MOVING
@ SPELL_FAILED_NOT_MOUNTED
@ SPELL_FAILED_AFFECTING_COMBAT
@ SPELL_FAILED_CASTER_AURASTATE
@ SPELL_FAILED_TARGET_NOT_PLAYER
@ SPELL_FAILED_NOT_KNOWN
@ SPELL_FAILED_FOOD_LOWLEVEL
@ SPELL_FAILED_NOT_STANDING
@ SPELL_FAILED_ROOTED
@ SPELL_FAILED_TARGET_NOT_DEAD
@ SPELL_FAILED_WRONG_PET_FOOD
@ SPELL_FAILED_BAD_IMPLICIT_TARGETS
@ SPELL_FAILED_TRY_AGAIN
@ SPELL_FAILED_NO_COMBO_POINTS
@ SPELL_FAILED_ALREADY_HAVE_SUMMON
@ SPELL_FAILED_ALREADY_OPEN
@ SPELL_FAILED_NOT_TRADING
@ SPELL_FAILED_ITEM_GONE
@ SPELL_FAILED_TARGET_NO_POCKETS
@ SPELL_FAILED_NO_MOUNTS_ALLOWED
@ SPELL_FAILED_ITEM_NOT_FOUND
@ SPELL_FAILED_OUT_OF_RANGE
@ SPELL_FAILED_IMMUNE
@ SPELL_FAILED_TARGET_DUELING
@ SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED
@ SPELL_FAILED_NOT_BEHIND
@ SPELL_FAILED_ALREADY_HAVE_CHARM
@ SPELL_FAILED_TARGET_NOT_IN_INSTANCE
@ SPELL_FAILED_HIGHLEVEL
@ SPELL_FAILED_DONT_REPORT
@ SPELL_FAILED_CANT_CAST_ON_TAPPED
@ SPELL_FAILED_TARGET_AURASTATE
@ SPELL_FAILED_TARGET_NOT_IN_RAID
@ SPELL_FAILED_LOWLEVEL
@ SPELL_FAILED_NOT_READY
@ SPELL_FAILED_ONLY_BATTLEGROUNDS
@ SPELL_FAILED_ONLY_STEALTHED
@ SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE
@ SPELL_FAILED_TARGETS_DEAD
@ SPELL_FAILED_AURA_BOUNCED
@ SPELL_FAILED_UNIT_NOT_BEHIND
@ SPELL_FAILED_CANT_BE_CHARMED
@ SPELL_FAILED_TARGET_NOT_GHOST
@ SPELL_FAILED_CASTER_DEAD
@ SPELL_FAILED_NO_DUELING
@ SPELL_FAILED_TARGET_UNSKINNABLE
@ SPELL_FAILED_TARGET_NO_WEAPONS
@ SPELL_FAILED_ONLY_OUTDOORS
@ SPELL_FAILED_CHARMED
@ SPELL_FAILED_LOW_CASTLEVEL
@ SPELL_FAILED_NOT_ON_TRANSPORT
@ SPELL_FAILED_LINE_OF_SIGHT
@ SPELL_FAILED_NO_PET
@ SPELL_FAILED_REQUIRES_SPELL_FOCUS
@ SPELL_FAILED_NOPATH
@ SPELL_FAILED_REQUIRES_AREA
@ SPELL_FAILED_TARGET_AFFECTING_COMBAT
@ SPELL_FAILED_ONLY_INDOORS
@ SPELL_FAILED_NOT_ON_TAXI
@ PETTAME_CREATUREALREADYOWNED
@ PETTAME_DEAD
@ PETTAME_UNITSCANTTAME
@ PETTAME_NOTTAMEABLE
@ PETTAME_CANTCONTROLEXOTIC
@ PETTAME_INVALIDCREATURE
@ PETTAME_TOOHIGHLEVEL
@ PETTAME_TOOMANY
@ PETTAME_ANOTHERSUMMONACTIVE
@ ERR_MOUNT_SHAPESHIFTED
@ ERR_MOUNT_LOOTING
@ SPELL_EXTRA_ERROR_NORTHREND_MINING
@ SPELL_EXTRA_ERROR_GM_ONLY
@ SPELLFAMILY_ROGUE
@ SPELLFAMILY_DRUID
@ SPELL_INFRONT_STATUS_REQUIRE_INBACK
@ SPELL_RANGED_THROW
@ SPELL_TARGET_AREA_MASK
Definition SpellTarget.h:52
@ SUMMON_CONTROL_TYPE_PET
@ SUMMONTYPE_PET
@ UNIT_FLAG_MOUNTED_TAXI
@ UNIT_FLAG_DISARMED
@ UNIT_FLAG_LOOTING
@ UNIT_FLAG_SKINNABLE
@ AURA_CHECK_RESULT_HIGHER_BUFF_PRESENT
@ FORM_DIREBEAR
@ FORM_TRAVEL
@ FORM_CREATUREBEAR
@ FORM_SPIRITOFREDEMPTION
@ FORM_DEMON
@ FORM_MOONKIN
@ FORM_CREATURECAT
@ FORM_CAT
@ FORM_FLIGHT
@ FORM_ZOMBIE
@ FORM_GHOSTWOLF
@ FORM_AQUA
@ FORM_METAMORPHOSIS
@ FORM_GHOUL
@ FORM_TREE
@ FORM_NORMAL
@ FORM_BEAR
@ MELEE
SERVER_DECL WDB::WDBContainer< WDB::Structures::GlyphPropertiesEntry > sGlyphPropertiesStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::SummonPropertiesEntry > sSummonPropertiesStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::CreatureFamilyEntry > sCreatureFamilyStore
Definition WDBStores.cpp:72
SERVER_DECL WDB::WDBContainer< WDB::Structures::LockEntry > sLockStore
Definition WDBStores.cpp:89
SERVER_DECL WDB::WDBContainer< WDB::Structures::AreaGroupEntry > sAreaGroupStore
#define LOCK_NUM_CASES
bool canCreatePath(float x, float y, float z)
MySQLStructure::MapInfo const * getMapInfo() const
Definition BaseMap.hpp:50
bool isRaid() const
Definition BaseMap.cpp:78
bool isWorldMap() const
Definition BaseMap.cpp:110
bool isBattleground() const
Definition BaseMap.cpp:85
bool isInCombat() const
bool HasMember(Player *pPlayer)
Definition Group.cpp:605
ItemProperties const * getItemProperties() const
Definition Item.cpp:954
bool m_isLocked
Definition Item.hpp:257
static WDB::Structures::AreaTableEntry const * GetAreaById(uint32_t area_id)
static bool IsOutdoor(uint32_t mapId, float x, float y, float z)
GameObject * getGameObjectNearestCoords(float x, float y, float z=0.0f, uint32_t Entry=0)
bool isInFront(Object *target)
Definition Object.cpp:3766
::WDB::Structures::AreaTableEntry const * GetArea() const
Definition Object.cpp:1766
Transporter * GetTransport() const
Definition Object.hpp:379
LocationVector & GetPositionNC()
Definition Object.hpp:374
uint32_t GetMapId() const
Definition Object.hpp:468
Player * getWorldMapPlayer(const uint64_t &guid) const
Definition Object.cpp:4586
bool IsWithinLOSInMap(Object *obj)
Definition Object.cpp:3604
const uint32_t & getZoneId() const
Definition Object.hpp:469
bool IsWithinLOS(LocationVector location)
Definition Object.cpp:3637
bool IsInMap(Object *obj)
Definition Object.hpp:442
SpellCastResult canLearnSpell(SpellInfo const *spellInfo) const
Definition Pet.cpp:1019
uint32_t getGlyphsEnabled() const
Definition Player.cpp:1312
uint8_t getPetCount() const
Definition Player.cpp:12323
uint16_t getSkillLineCurrent(uint16_t skillLine, bool includeBonus=true) const
Definition Player.cpp:4928
bool isMoving() const
Definition Player.cpp:1510
TradeData * getTradeData() const
Definition Player.cpp:6506
std::optional< uint8_t > findFreeActivePetSlot() const
Definition Player.cpp:12349
PetCache const * getPetCache(uint8_t petId) const
Definition Player.cpp:12276
bool hasSpellGlobalCooldown(SpellInfo const *spellInfo)
Definition Player.cpp:4330
bool hasPlayerFlags(uint32_t flags) const
Definition Player.cpp:786
bool canUseFlyingMountHere()
Definition Player.cpp:4210
bool hasSpellOnCooldown(SpellInfo const *spellInfo)
Definition Player.cpp:4298
bool m_isGmInvisible
Definition Player.hpp:1096
WorldSession * getSession() const
Definition Player.cpp:3131
void sendMountResultPacket(uint32_t result)
Definition Player.cpp:9704
uint32_t getCategoryRecoveryTime() const
int32_t getEffectMiscValueB(uint8_t idx) const
uint32_t getAttributesExB() const
bool hasEffect(uint32_t effect) const
uint32_t getAttributesExC() const
uint32_t getRequiredTargetMask(bool getExplicitMask) const
int32_t getRequiresAreaId() const
uint32_t getRecoveryTime() const
uint32_t getDispelType() const
bool hasExplicitTarget(uint32_t value) const
int32_t calculateEffect(uint8_t effIndex)
Definition Spell.cpp:1469
void setTargetConstraintCreature(Creature *_creature)
Definition Spell.cpp:5699
void SendTameFailure(uint8_t failure)
SpellCastResult checkItems(uint32_t *parameter1, uint32_t *parameter2) const
Definition Spell.cpp:3295
SpellCastResult checkShapeshift(SpellInfo const *spellInfo, const uint32_t shapeshiftForm) const
Definition Spell.cpp:4486
SpellCastResult checkCasterState() const
Definition Spell.cpp:4114
void setTargetConstraintGameObject(GameObject *_gameobject)
Definition Spell.cpp:5702
bool canAttackCreatureType(Creature *target) const
Definition Spell.cpp:6002
uint8_t CanCast(bool)
SpellCastResult checkRange(const bool secondCheck)
Definition Spell.cpp:4296
SpellCastResult checkPower()
Definition Spell.cpp:3250
void setTradeSpell(uint32_t spell_id, Item *cast_item=nullptr)
bool isTagged() const
Definition Unit.cpp:8125
bool isInvisible() const
Definition Unit.cpp:6230
bool isSitting() const
Definition Unit.cpp:7054
bool hasAuraState(AuraState state, SpellInfo const *spellInfo=nullptr, Unit const *caster=nullptr) const
Definition Unit.cpp:5130
uint64_t getTargetGuid() const
Definition Unit.cpp:400
uint64_t getCharmGuid() const
Definition Unit.cpp:380
uint64_t getTaggerGuid() const
Definition Unit.cpp:8120
WDB::Structures::MountCapabilityEntry const * getMountCapability(uint32_t mountType)
Definition Unit.cpp:8016
bool canSee(Object *const obj)
Definition Unit.cpp:5845
uint8_t getShapeShiftForm() const
Definition Unit.cpp:1386
bool hasAuraWithAuraEffect(AuraEffect type) const
Definition Unit.cpp:5060
Pet * getPet() const
Definition Unit.cpp:7929
AIInterface * getAIInterface() const
Definition Unit.hpp:705
Loot loot
Definition Unit.hpp:1221
bool isStealthed() const
Definition Unit.cpp:6205
uint32_t getLevel() const
Definition Unit.cpp:936
CombatHandler & getCombatHandler()
Definition Unit.cpp:1803
BaseMap * getBaseMap() const
Definition WorldMap.hpp:320
bool HasGMPermissions() const
uint32_t Error
Definition Unit.hpp:133
struct GameObjectProperties::@162::@164 door
bool isLooted() const
Definition Loot.hpp:65
unsigned short uint16_t
@ IN_MILLISECONDS
Definition Definitions.h:18
@ MINUTE
Definition Definitions.h:12
Here is the caller graph for this function:

◆ cancel()

void Spell::cancel ( )

Definition at line 1394 of file Spell.cpp.

1395{
1396 switch (getState())
1397 {
1399 {
1400 if (getPlayerCaster() != nullptr)
1402
1403 SendInterrupted(0);
1405 } break;
1407 {
1409 SendInterrupted(0);
1411
1412 if (getUnitCaster() != nullptr)
1413 {
1414 if (m_timer > 0 || m_Delayed)
1415 {
1416 auto channelTarget = getUnitCaster()->getWorldMapUnit(getUnitCaster()->getChannelObjectGuid());
1417 if (channelTarget == nullptr && getPlayerCaster() != nullptr)
1418 channelTarget = getPlayerCaster()->getWorldMapUnit(getPlayerCaster()->getTargetGuid());
1419
1420 if (channelTarget != nullptr)
1421 channelTarget->removeAllAurasByIdForGuid(getSpellInfo()->getId(), getCaster()->getGuid());
1422
1423 // Remove dynamic objects (area aura effects from Blizzard, Rain of Fire etc)
1424 if (m_AreaAura)
1425 {
1426 const auto dynObj = getUnitCaster()->getWorldMapDynamicObject(getUnitCaster()->getChannelObjectGuid());
1427 if (dynObj != nullptr)
1428 dynObj->remove();
1429 }
1430
1431 if (getPlayerCaster() != nullptr && getPlayerCaster()->getSummonedObject() != nullptr)
1432 {
1433 auto obj = getPlayerCaster()->getSummonedObject();
1434 if (obj->IsInWorld())
1435 obj->RemoveFromWorld(true);
1436
1437 delete obj;
1439 }
1440
1441 if (m_timer > 0)
1443 }
1444
1446 }
1447 } break;
1448 case SPELL_STATE_CASTED:
1449 break;
1450 default:
1451 {
1452 if (getState() == SPELL_STATE_NULL)
1453 {
1454 // just in case
1455 if (getCaster() != nullptr)
1457 else
1458 delete this;
1459 }
1460 } return;
1461 }
1462
1463 // If this is true, the spell is somewhere in ::castMe() function
1464 // In that case, ::finish() will be called when the spell has hitted targets
1466 finish(false);
1467}
@ SPELL_FAILED_INTERRUPTED
@ SPELL_STATE_CHANNELING
@ SPELL_STATE_CASTED
@ SPELL_STATE_NULL
void removeTravelingSpell(Spell *spell)
Definition Object.cpp:1486
DynamicObject * getWorldMapDynamicObject(const uint64_t &guid) const
Definition Object.cpp:4619
virtual void RemoveFromWorld(bool free_guid)
Remove object from world.
Definition Object.cpp:3524
void clearGlobalCooldown()
Definition Player.cpp:4449
void setSummonedObject(Object *summonedObject)
Definition Player.cpp:12705
uint32_t getState() const
void SendInterrupted(uint8_t result)
void finish(bool successful=true)
Definition Spell.cpp:1076
void removeCastItem()
Definition Spell.cpp:6013
void sendCastResult(SpellCastResult result, uint32_t parameter1=0, uint32_t parameter2=0)
Definition Spell.cpp:4552
void removeAllAurasByIdForGuid(uint32_t auraId, uint64_t guid, AuraRemoveMode mode=AURA_REMOVE_BY_SERVER)
Definition Unit.cpp:5274
Here is the call graph for this function:
Here is the caller graph for this function:

◆ castMe()

void Spell::castMe ( const bool  doReCheck)

Definition at line 425 of file Spell.cpp.

426{
428
430 {
433 finish(false);
434 return;
435 }
436
437 // Debug logging
438 if (m_caster->isPlayer())
439 {
440 const auto plr = static_cast<Player*>(m_caster);
441 sLogger.debugFlag(AscEmu::Logging::LF_SPELL, "Spell::castMe : Player guid {} casted spell {} (id {})",
442 plr->getGuidLow(), getSpellInfo()->getName(), getSpellInfo()->getId());
443 }
444 else if (m_caster->isCreature())
445 {
446 const auto creature = static_cast<Creature*>(m_caster);
447 sLogger.debugFlag(AscEmu::Logging::LF_SPELL, "Spell::castMe : Creature guid {} (entry {}) casted spell {} (id {})",
448 creature->spawnid, creature->getEntry(), getSpellInfo()->getName(), getSpellInfo()->getId());
449 }
450 else
451 {
452 sLogger.debugFlag(AscEmu::Logging::LF_SPELL, "Spell::castMe : Spell id {} casted, caster guid {}", getSpellInfo()->getId(), m_caster->getGuid());
453 }
454
455 // Check cast again if spell had cast time
456 if (doReCheck)
457 {
458 // Recalculate power cost in case caster gained a mana reduction buff while casting (blizzlike)
459 m_powerCost = i_caster != nullptr ? 0 : calculatePowerCost();
460
461 uint32_t parameter1 = 0, parameter2 = 0;
462 cancastresult = canCast(true, &parameter1, &parameter2);
464 {
465 sendCastResult(cancastresult, parameter1, parameter2);
467 finish(false);
468 return;
469 }
470 }
471
472 // Remove stealth if spell is an instant cast
473 if (!m_triggeredSpell && m_castTime == 0 && p_caster != nullptr)
474 {
475 if (!(getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_NOT_BREAK_STEALTH))
477
478 // Remove Feign Death auras
480 }
481
482 // Initialize targets
483 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
484 {
485 const auto requiredTargetMask = getSpellInfo()->getRequiredTargetMaskForEffect(i);
486 if (requiredTargetMask & SPELL_TARGET_AREA_CURTARGET)
487 {
488 // If target type is area around target, set destination correctly
489 const auto targetObj = m_caster->getWorldMapObject(m_targets.getUnitTargetGuid());
490 if (targetObj != nullptr)
491 {
493 m_targets.setDestination(targetObj->GetPosition());
494 }
495 }
496
497 if (getSpellInfo()->getEffect(i) != 0 && getSpellInfo()->getEffect(i) != SPELL_EFFECT_PERSISTENT_AREA_AURA)
498 FillTargetMap(i);
499
500 // Call for scripted filter target hook
501 sScriptMgr.callScriptedSpellFilterTargets(this, i, &m_effectTargets[i]);
502 }
503
504 // Check for magnet target (Grounding Totem)
505 //\ todo: move this to ::handleeffects or something
506 if (m_magnetTarget != 0)
507 {
508 // Spell was redirected
509 // Grounding Totem gets destroyed after redirecting 1 spell
510 const auto magnetTarget = m_caster->getWorldMapUnit(m_magnetTarget);
511 if (magnetTarget != nullptr && magnetTarget->isCreature())
512 {
513 const auto creatureMagnet = static_cast<Creature*>(magnetTarget);
514 if (creatureMagnet->isTotem())
515 creatureMagnet->Despawn(1, 0);
516 }
517 m_magnetTarget = 0;
518 }
519
520 // Send cooldown
521 if (p_caster != nullptr && !(getSpellInfo()->getAttributes() & (ATTRIBUTES_PASSIVE | ATTRIBUTES_TRIGGER_COOLDOWN)))
522 {
523 // Ranged shoot spells (throw, wand shoot etc) don't have cooldowns set in DBC
524 // The cooldown is the speed of equipped ranged weapon
526 {
527 const auto cooldown = static_cast<int32_t>(p_caster->getBaseAttackTime(RANGED));
528 p_caster->addSpellCooldown(getSpellInfo(), i_caster, this, cooldown);
529 }
530 else
531 {
533 }
534 }
535
536 // Take power
538 {
540 {
541 // When on next melee spell is actually casted it will be a triggered spell
542 // Need to check for power here (canCast skips power check for triggered spells)
543 const auto powerResult = checkPower();
544 if (powerResult != SPELL_CAST_SUCCESS)
545 {
546 // Normally error messages are not sent for triggered spells but this is an exception
547 sendCastResult(powerResult);
549 finish(false);
550 return;
551 }
552
553 takePower();
554 }
555 }
556 else
557 {
558 takePower();
559 }
560
561 // Remove reagents before handling effects so crafted item can be put in same slot
563#if VERSION_STRING < Cata
564 removeAmmo();
565#endif
566
567 // TODO: REMOVE ME; hackfixes from legacy Spell::castMe()
568 castMeOld();
569
570 // Activate on next melee spell
571 // Spell is casted on next melee spell as a triggered spell
572 if (getSpellInfo()->isOnNextMeleeAttack() && !m_triggeredSpell)
573 {
574 if (u_caster != nullptr)
575 {
576 if (m_triggeredByAura == nullptr && !(getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_NOT_BREAK_STEALTH))
577 {
578 // we're much better to remove this here, because otherwise spells that change powers etc,
579 // don't get applied.
582 }
583
585 }
586
587 finish();
588 return;
589 }
590
591 // Fill unique hitted targets
592 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
593 {
594 if (getSpellInfo()->getEffect(i) == 0)
595 continue;
596
597 for (const auto& targetGuid : m_effectTargets[i])
598 {
599 if (targetGuid == 0)
600 continue;
601
602 // Add only if target is not already stored in the vector
603 auto add = true;
604 for (const auto& uniqueTarget : m_uniqueHittedTargets)
605 {
606 if (uniqueTarget.first == targetGuid)
607 {
608 add = false;
609 break;
610 }
611 }
612
613 if (add)
614 m_uniqueHittedTargets.push_back(std::make_pair(targetGuid, DamageInfo()));
615 }
616 }
617
618 // Cleanup missed targets; spell either hits or misses target, not both
619 // Current spell target system is bullshit
620 if (!m_missedTargets.empty())
621 {
622 for (const auto& targetGuid : m_uniqueHittedTargets)
623 {
624 auto missedTarget = m_missedTargets.begin();
625 while (missedTarget != m_missedTargets.end())
626 {
627 if (missedTarget->targetGuid == targetGuid.first)
628 missedTarget = m_missedTargets.erase(missedTarget);
629 else
630 ++missedTarget;
631 }
632 }
633 }
634
635 // Send spell missile/visual effect
636 sendSpellGo();
637
638 uint32_t channelDuration = 0;
639 if (getSpellInfo()->isChanneled())
640 {
641 if (getDuration() > 0)
642 {
643 channelDuration = static_cast<uint32_t>(getDuration());
644 sendChannelStart(channelDuration);
646 }
647 else if (getDuration() == -1)
648 {
649 sendChannelStart(static_cast<uint32_t>(getDuration()));
651 }
652 }
653
654 // Set cooldown on item after SMSG_SPELL_GO
655 if (i_caster != nullptr && i_caster->getOwner() != nullptr && !GetSpellFailed())
656 {
657 // Potion cooldown starts after leaving combat
659 {
662 }
663 else
664 {
665 for (uint8_t spellIndex = 0; spellIndex < MAX_ITEM_PROTO_SPELLS; ++spellIndex)
666 {
667 const auto& itemSpell = i_caster->getItemProperties()->Spells[spellIndex];
668 if (itemSpell.Id != 0 && itemSpell.Trigger == USE)
670 }
671 }
672 }
673
674 // Take cast item after SMSG_SPELL_GO but before effect handling
675 if (!GetSpellFailed())
677
678#if VERSION_STRING < Cata
679 /*
680 Five Second Rule
681 After a character expends mana in casting a spell, the effective amount of mana gained per tick from spirit-based regeneration becomes a ratio of the normal
682 listed above, for a period of 5 seconds. During this period mana regeneration is said to be interrupted. This is commonly referred to as the five second rule.
683 By default, your interrupted mana regeneration ratio is 0%, meaning that spirit-based mana regeneration is suspended for 5 seconds after casting.
684
685 Channeled spells are handled a little differently. The five second rule starts when the spell's channeling starts; i.e. when you pay the mana for it.
686 The rule continues for at least five seconds, and longer if the spell is channeled for more than five seconds. For example,
687 Mind Flay channels for 3 seconds and interrupts your regeneration for 5 seconds, while Tranquility channels for 10 seconds
688 and interrupts your regeneration for the full 10 seconds.
689 */
690 if (m_usesMana && u_caster != nullptr)
691 u_caster->interruptPowerRegeneration(std::max(channelDuration, 5000u));
692#endif
693
694 // we're much better to remove this here, because otherwise spells that change powers etc,
695 // don't get applied.
697 {
700 }
701
702 // Prepare proc flags for caster and targets
705
706 // Loop through spell effects and process the spell effect on each target
707 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
708 {
709 const auto spellEffect = getSpellInfo()->getEffect(i);
710 if (spellEffect == SPELL_EFFECT_NULL)
711 continue;
712
713 // Call for scripted before hit hook
714 sScriptMgr.callScriptedSpellBeforeHit(this, i);
715
716 if (!m_effectTargets[i].empty())
717 {
718 for (const auto& targetGuid : m_effectTargets[i])
719 {
720 handleHittedTarget(targetGuid, i);
721 }
722 }
723 else
724 {
725 handleHittedTarget(0, i);
726 }
727 }
728
729 // If spell applies an aura, handle it to targets after all effects have been processed
730 if (!m_pendingAuras.empty())
731 {
732 for (auto itr = m_pendingAuras.begin(); itr != m_pendingAuras.end();)
733 {
734 const auto& pendingAur = *itr;
735 // Handle only instant auras here
736 if (pendingAur.second.travelTime > 0)
737 {
738 ++itr;
739 continue;
740 }
741
742 HandleAddAura(pendingAur.first);
743 itr = m_pendingAuras.erase(itr);
744 }
745 }
746
747 // Handle targets who did not get hit by this spell (miss/resist etc)
748 auto targetMissed = false, targetDodged = false, targetParried = false;
749 for (const auto& missedTarget : m_missedTargets)
750 {
751 handleMissedTarget(missedTarget);
752
753 // Check if any target missed, dodged or parried the spell
754 if (missedTarget.hitResult == SPELL_DID_HIT_MISS)
755 targetMissed = true;
756 else if (missedTarget.hitResult == SPELL_DID_HIT_DODGE)
757 targetDodged = true;
758 else if (missedTarget.hitResult == SPELL_DID_HIT_PARRY)
759 targetParried = true;
760 }
761
762 // Handle used spell modifiers
764
765 if (u_caster != nullptr)
766 {
767 // Reset attack timer
768 if (!m_triggeredSpell && getSpellInfo()->getInterruptFlags() & CAST_INTERRUPT_ON_AUTOATTACK && !(getSpellInfo()->getAttributesExB() & ATTRIBUTESEXB_NOT_RESET_AUTO_ATTACKS))
769 {
771 //\ todo: fix this for creatures
772 if (p_caster != nullptr && p_caster->hasOffHandWeapon())
774 }
775
776 if (p_caster != nullptr)
777 {
778 // Druids and rogues are refunded for 82% of the energy cost on miss, dodge or parry
779 if (getSpellInfo()->getPowerType() == POWER_TYPE_ENERGY && getSpellInfo()->hasEffect(SPELL_EFFECT_ADD_COMBO_POINTS) &&
780 (targetMissed || targetDodged || targetParried))
781 {
782 const auto refundCost = Util::float2int32(getPowerCost() * 0.82f);
783 p_caster->modPower(POWER_TYPE_ENERGY, refundCost);
784 }
785 // Druids and warriors are refunded for 82% of the rage cost on dodge or parry
786 else if (getSpellInfo()->getPowerType() == POWER_TYPE_RAGE &&
787 (targetDodged || targetParried))
788 {
789 const auto refundCost = Util::float2int32(getPowerCost() * 0.82f);
790 p_caster->modPower(POWER_TYPE_RAGE, refundCost);
791 }
792
793 // This is wrong but leaving this here commented out for now -Appled
794 // This needs to be handled somewhere
795 //Target->removeAuraStateAndAuras(static_cast<AuraState>(getSpellInfo()->getTargetAuraState()));
796 }
797 }
798
799 // If spell is not channeled, the spell cast has finished successfully and the spell is traveling
800 // Spells without travel time are also finished on next update tick
802 {
805 }
806}
@ SPELL_AURA_FEIGN_DEATH
@ AURA_INTERRUPT_ON_CAST_SPELL
@ AURA_INTERRUPT_ON_CAST
@ CAST_INTERRUPT_ON_AUTOATTACK
@ USE
@ ITEM_CLASS_CONSUMABLE
@ ITEM_SUBCLASS_POTION
#define MAX_ITEM_PROTO_SPELLS
@ POWER_TYPE_RAGE
Definition PowerType.hpp:14
@ POWER_TYPE_ENERGY
Definition PowerType.hpp:16
SchoolMask
Definition School.hpp:23
@ TARGET_FLAG_DEST_LOCATION
@ ATTRIBUTESEXB_NOT_RESET_AUTO_ATTACKS
@ ATTRIBUTESEX_NOT_BREAK_STEALTH
@ ATTRIBUTESEXC_PLAYER_RANGED_SPELLS
@ ATTRIBUTES_PASSIVE
@ ATTRIBUTES_TRIGGER_COOLDOWN
@ SPELL_DID_HIT_MISS
@ SPELL_DID_HIT_DODGE
@ SPELL_DID_HIT_PARRY
@ SPELL_EFFECT_ADD_COMBO_POINTS
@ SPELL_EFFECT_NULL
@ SPELL_EFFECT_PERSISTENT_AREA_AURA
@ SPELL_STATE_TRAVELING
@ RANGED
virtual void Despawn(uint32_t delay, uint32_t respawntime)
void addTravelingSpell(Spell *spell)
Definition Object.cpp:1481
void updatePotionCooldown()
Definition Player.cpp:4532
void addSpellCooldown(SpellInfo const *spellInfo, Item const *itemCaster, Spell *castingSpell=nullptr, int32_t cooldownTime=0)
Definition Player.cpp:4347
bool hasOffHandWeapon() const
Definition Player.cpp:6629
void cooldownAddItem(ItemProperties const *itemProp, uint32_t spellIndex)
Definition Player.cpp:4478
void setLastPotion(uint32_t itemId)
Definition Player.hpp:904
void setTargetMask(uint32_t mask)
std::string const & getName() const
bool isOnNextMeleeAttack() const
uint32_t getId() const
uint32_t getPowerCost() const
Definition Spell.cpp:5552
void takeUsedSpellModifiers()
Definition Spell.cpp:5882
SpellCastResult cancastresult
Definition Spell.hpp:337
virtual SpellCastResult canCast(const bool secondCheck, uint32_t *parameter1, uint32_t *parameter2)
Definition Spell.cpp:1560
uint32_t m_powerCost
Definition Spell.hpp:136
void HandleAddAura(uint64_t guid)
void removeReagents()
Definition Spell.cpp:6069
DamageInfo m_casterDamageInfo
Definition Spell.hpp:312
void sendChannelStart(const uint32_t duration)
Definition Spell.cpp:5273
bool m_usesMana
Definition Spell.hpp:138
bool DuelSpellNoMoreValid() const
void FillTargetMap(uint32_t)
uint32_t calculatePowerCost()
Definition Spell.cpp:5595
void handleHittedTarget(const uint64_t targetGuid, uint8_t effIndex)
Definition Spell.cpp:808
void castMeOld()
bool GetSpellFailed() const
void _prepareProcFlags()
Definition Spell.cpp:6322
void handleMissedTarget(SpellTargetMod const missedTarget)
Definition Spell.cpp:962
void takePower()
Definition Spell.cpp:5557
void modPower(PowerType type, int32_t value)
Definition Unit.cpp:614
void setOnMeleeSpell(uint32_t spellId, uint8_t ecn=0)
Definition Unit.hpp:1333
void setAttackTimer(WeaponDamageType type, uint32_t time)
Definition Unit.cpp:6902
void removeAllAurasByAuraEffect(AuraEffect effect, uint32_t skipSpell=0, bool removeOnlyEffect=false, uint64_t casterGuid=0, AuraRemoveMode mode=AURA_REMOVE_BY_SERVER)
Definition Unit.cpp:5306
void removeAllAurasByAuraInterruptFlag(uint32_t auraInterruptFlag, uint32_t skipSpellId=0)
Definition Unit.cpp:5290
static int add(void *a, void *b, void *c)
Definition ltm_desc.c:207
int32_t float2int32(float value)
Definition Narrow.cpp:18
SchoolMask schoolMask
ItemSpell Spells[MAX_ITEM_PROTO_SPELLS]
Here is the caller graph for this function:

◆ castMeOld()

void Spell::castMeOld ( )

Definition at line 852 of file Spell.Legacy.cpp.

853{
854 if (p_caster)
855 {
856 switch (getSpellInfo()->getId())
857 {
858 //SPELL_HASH_SLAM
859 case 1464:
860 case 8820:
861 case 11430:
862 case 11604:
863 case 11605:
864 case 25241:
865 case 25242:
866 case 34620:
867 case 47474:
868 case 47475:
869 case 50782:
870 case 50783:
871 case 52026:
872 case 67028:
873 {
876 } break;
877
878 //SPELL_HASH_VICTORY_RUSH
879 case 34428:
880 {
882 } break;
883
884 //SPELL_HASH_HOLY_LIGHT
885 case 635:
886 case 639:
887 case 647:
888 case 1026:
889 case 1042:
890 case 3472:
891 case 10328:
892 case 10329:
893 case 13952:
894 case 15493:
895 case 25263:
896 case 25292:
897 case 27135:
898 case 27136:
899 case 29383:
900 case 29427:
901 case 29562:
902 case 31713:
903 case 32769:
904 case 37979:
905 case 43451:
906 case 44479:
907 case 46029:
908 case 48781:
909 case 48782:
910 case 52444:
911 case 56539:
912 case 58053:
913 case 66112:
914 case 68011:
915 case 68012:
916 case 68013:
917 //SPELL_HASH_FLASH_OF_LIGHT
918 case 19750:
919 case 19939:
920 case 19940:
921 case 19941:
922 case 19942:
923 case 19943:
924 case 25514:
925 case 27137:
926 case 33641:
927 case 37249:
928 case 37254:
929 case 37257:
930 case 48784:
931 case 48785:
932 case 57766:
933 case 59997:
934 case 66113:
935 case 66922:
936 case 68008:
937 case 68009:
938 case 68010:
939 case 71930:
940 {
943 } break;
944 }
945
946 if (getSpellInfo()->custom_c_is_flags == SPELL_FLAG_IS_DAMAGING)
947 {
948 uint32_t arcanePotency[] =
949 {
950 //SPELL_HASH_ARCANE_POTENCY
951 24544,
952 31571,
953 31572,
954 33421,
955 33713,
956 57529,
957 57531,
958 0
959 };
960 if (p_caster->hasAurasWithId(arcanePotency))
961 {
964 }
965 }
966
968 && getSpellInfo()->getId() != 1) //check spells that get trigger spell 1 after spell loading
969 {
970 /* talents procing - don't remove stealth either */
971 if (!hasAttribute(ATTRIBUTES_PASSIVE) && !(pSpellId && sSpellMgr.getSpellInfo(pSpellId)->isPassive()))
972 {
974 }
975 }
976
977 // special case battleground additional actions
979 {
980
981 // warsong gulch & eye of the storm flag pickup check
982 // also includes check for trying to cast stealth/etc while you have the flag
983 switch (getSpellInfo()->getId())
984 {
985 case 21651:
986 {
987 // Arathi Basin opening spell, remove stealth, invisibility, etc.
990
991 uint32_t divineShield[] =
992 {
993 //SPELL_HASH_DIVINE_SHIELD
994 642,
995 13874,
996 29382,
997 33581,
998 40733,
999 41367,
1000 54322,
1001 63148,
1002 66010,
1003 67251,
1004 71550,
1005 0
1006 };
1007 p_caster->removeAllAurasById(divineShield);
1008
1009 uint32_t divineProtection[] =
1010 {
1011 //SPELL_HASH_DIVINE_PROTECTION
1012 498,
1013 13007,
1014 27778,
1015 27779,
1016 0
1017 };
1018 p_caster->removeAllAurasById(divineProtection);
1019 //SPELL_HASH_BLESSING_OF_PROTECTION
1021 } break;
1022 case 23333:
1023 case 23335:
1024 case 34976:
1025 {
1026 // if we're picking up the flag remove the buffs
1029
1030 uint32_t divineShield[] =
1031 {
1032 //SPELL_HASH_DIVINE_SHIELD
1033 642,
1034 13874,
1035 29382,
1036 33581,
1037 40733,
1038 41367,
1039 54322,
1040 63148,
1041 66010,
1042 67251,
1043 71550,
1044 0
1045 };
1046 p_caster->removeAllAurasById(divineShield);
1047
1048 uint32_t divineProtection[] =
1049 {
1050 //SPELL_HASH_DIVINE_PROTECTION
1051 498,
1052 13007,
1053 27778,
1054 27779,
1055 0
1056 };
1057 p_caster->removeAllAurasById(divineProtection);
1058 //SPELL_HASH_BLESSING_OF_PROTECTION
1060 } break;
1061 // cases for stealth - etc
1062 // we can cast the spell, but we drop the flag (if we have it)
1063 case 1784: // Stealth rank 1
1064 case 1785: // Stealth rank 2
1065 case 1786: // Stealth rank 3
1066 case 1787: // Stealth rank 4
1067 case 5215: // Prowl rank 1
1068 case 6783: // Prowl rank 2
1069 case 9913: // Prowl rank 3
1070 case 498: // Divine protection
1071 case 5573: // Unknown spell
1072 case 642: // Divine shield
1073 case 1020: // Unknown spell
1074 case 1022: // Hand of Protection rank 1 (ex blessing of protection)
1075 case 5599: // Hand of Protection rank 2 (ex blessing of protection)
1076 case 10278: // Hand of Protection rank 3 (ex blessing of protection)
1077 case 1856: // Vanish rank 1
1078 case 1857: // Vanish rank 2
1079 case 26889: // Vanish rank 3
1080 case 45438: // Ice block
1081 case 20580: // Unknown spell
1082 case 58984: // Shadowmeld
1083 case 17624: // Petrification-> http://www.wowhead.com/?spell=17624
1084 case 66: // Invisibility
1086 {
1087 if (p_caster->getTeam() == 0)
1088 p_caster->removeAllAurasById(23333); // ally player drop horde flag if they have it
1089 else
1090 p_caster->removeAllAurasById(23335); // horde player drop ally flag if they have it
1091 }
1093
1094 p_caster->removeAllAurasById(34976); // drop the flag
1095 break;
1096 }
1097 }
1098 }
1099}
@ SPELL_AURA_MOD_INVISIBILITY
@ AURASTATE_FLAG_LASTKILLWITHHONOR
@ SPELL_FLAG_IS_DAMAGING
uint32_t getType()
PlayerTeam getTeam() const
Definition Player.cpp:2774
bool hasAttributeEx(SpellAttributesEx _attribute) const
Definition Spell.cpp:5799
bool hasAttribute(SpellAttributes _attribute) const
Definition Spell.cpp:5794
void removeAuraStateAndAuras(AuraState state)
Definition Unit.cpp:5168
void removeAllAurasById(uint32_t auraId, AuraRemoveMode mode=AURA_REMOVE_BY_SERVER)
Definition Unit.cpp:5248
Here is the call graph for this function:
Here is the caller graph for this function:

◆ checkCasterState()

SpellCastResult Spell::checkCasterState ( ) const
private

Definition at line 4114 of file Spell.cpp.

4115{
4116 // Skip for non-unit casters
4117 if (u_caster == nullptr)
4118 return SPELL_CAST_SUCCESS;
4119
4120 // Spells with this attribute are casted regardless of caster's state or auras
4122 return SPELL_CAST_SUCCESS;
4123
4124 // Spells that have following attributes should be casted regardless of caster's state
4125 // Includes tons of quest and achievement credit spells, and some battleground spells (flag drops, marks, honor spells)
4126 if (getSpellInfo()->getAttributes() & ATTRIBUTES_DEAD_CASTABLE &&
4127 getSpellInfo()->getAttributesExB() & ATTRIBUTESEXB_IGNORE_LINE_OF_SIGHT &&
4128 getSpellInfo()->getAttributesExC() & ATTRIBUTESEXC_HIGH_PRIORITY)
4129 return SPELL_CAST_SUCCESS;
4130
4131 uint16_t schoolImmunityMask = 0, dispelImmunityMask = 0;
4132 uint32_t mechanicImmunityMask = 0;
4133 if (getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_DISPEL_AURAS_ON_IMMUNITY)
4134 {
4135 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
4136 {
4137 switch (getSpellInfo()->getEffectApplyAuraName(i))
4138 {
4140 // This is already stored in bitmask
4141 schoolImmunityMask |= static_cast<uint16_t>(getSpellInfo()->getEffectMiscValue(i));
4142 break;
4144 mechanicImmunityMask |= 1 << static_cast<uint32_t>(getSpellInfo()->getEffectMiscValue(i) - 1);
4145 break;
4147 mechanicImmunityMask |= static_cast<uint32_t>(getSpellInfo()->getEffectMiscValue(i));
4148 break;
4150 {
4151 const uint16_t dispelMaskAll = (1 << DISPEL_MAGIC) | (1 << DISPEL_CURSE) | (1 << DISPEL_DISEASE) | (1 << DISPEL_POISON);
4152 dispelImmunityMask |= getSpellInfo()->getEffectMiscValue(i) == DISPEL_ALL ? dispelMaskAll : static_cast<uint16_t>(1 << getSpellInfo()->getEffectMiscValue(i));
4153 } break;
4154 default:
4155 break;
4156 }
4157 }
4158
4159 // Check if the spell is a pvp trinket alike spell (removes all movement impairement and loss of control effects)
4161 getSpellInfo()->getEffectMiscValue(0) == 1 &&
4163 mechanicImmunityMask = MOVEMENT_IMPAIRMENTS_AND_LOSS_OF_CONTROL_MASK;
4164 }
4165
4166 // Helper lambda for checking if spell has a mechanic
4167 const auto hasSpellMechanic = [](SpellInfo const* spellInfo, SpellMechanic mechanic) -> bool
4168 {
4169 if (spellInfo->getMechanicsType() == mechanic)
4170 return true;
4171
4172 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
4173 {
4174 if (spellInfo->getEffectMechanic(i) == mechanic)
4175 return true;
4176 }
4177
4178 return false;
4179 };
4180
4183 {
4185 {
4186 // Spell is usable while stunned, but there are some spells with stun effect which are not classified as normal stun spells
4187 for (const auto& aurEff : getUnitCaster()->getAuraEffectList(SPELL_AURA_MOD_STUN))
4188 {
4189 const auto* stunAura = aurEff->getAura();
4190 // Frozen mechanic acts like stunned mechanic
4191 if (!hasSpellMechanic(stunAura->getSpellInfo(), MECHANIC_STUNNED)
4192 && !hasSpellMechanic(stunAura->getSpellInfo(), MECHANIC_FROZEN))
4193 {
4194 // The stun aura has a stun effect but has no stun or frozen mechanic
4195 // This is not a normal stun aura
4196 errorMsg = SPELL_FAILED_STUNNED;
4197 break;
4198 }
4199 }
4200 }
4201 else
4202 {
4203 errorMsg = SPELL_FAILED_STUNNED;
4204 }
4205 }
4207 {
4208 errorMsg = SPELL_FAILED_CONFUSED;
4209 }
4211 {
4212 errorMsg = SPELL_FAILED_FLEEING;
4213 }
4214 else if (u_caster->hasUnitFlags(UNIT_FLAG_SILENCED) && getSpellInfo()->getPreventionType() == PREVENTION_TYPE_SILENCE)
4215 {
4216 errorMsg = SPELL_FAILED_SILENCED;
4217 }
4218 else if (u_caster->hasUnitStateFlag(UNIT_FLAG_PACIFIED) && getSpellInfo()->getPreventionType() == PREVENTION_TYPE_PACIFY)
4219 {
4220 errorMsg = SPELL_FAILED_PACIFIED;
4221 }
4222
4223 if (errorMsg != SPELL_CAST_SUCCESS)
4224 {
4225 if (schoolImmunityMask > 0 || dispelImmunityMask > 0 || mechanicImmunityMask > 0)
4226 {
4227 // The spell cast is prevented by some state but check if the spell is unaffected by those states or grants immunity to those states
4228 for (const auto& aur : getUnitCaster()->getAuraList())
4229 {
4230 if (aur == nullptr)
4231 continue;
4232
4233 // Check if the spell, which is being casted, is unaffected by this aura due to school immunity
4234 if (aur->getSpellInfo()->getSchoolMask() & schoolImmunityMask && !(aur->getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_UNAFFECTED_BY_SCHOOL_IMMUNE))
4235 continue;
4236
4237 // Check if the spell, which is being casted, is unaffected by this aura due to dispel immunity
4238 if ((1 << aur->getSpellInfo()->getDispelType()) & dispelImmunityMask)
4239 continue;
4240
4241 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
4242 {
4243 if (aur->getSpellInfo()->getEffectApplyAuraName(i) == 0)
4244 continue;
4245
4246 // Get aura's mechanics in one mask
4247 uint32_t mechanicMask = 0;
4248 if (aur->getSpellInfo()->getMechanicsType() > 0)
4249 mechanicMask |= 1 << (aur->getSpellInfo()->getMechanicsType() - 1);
4250 if (aur->getSpellInfo()->getEffectMechanic(i) > 0)
4251 mechanicMask |= 1 << (aur->getSpellInfo()->getEffectMechanic(i) - 1);
4252
4253 // Check if the spell, which is being casted, is unaffected by this aura due to mechanic immunity
4254 if (mechanicMask & mechanicImmunityMask)
4255 continue;
4256
4257 // Spell cast is prevented by this aura and by this effect index, return correct error message
4258 switch (aur->getSpellInfo()->getEffectApplyAuraName(i))
4259 {
4261 if (!(getSpellInfo()->getAttributesExE() & ATTRIBUTESEXE_USABLE_WHILE_STUNNED) || !hasSpellMechanic(getSpellInfo(), MECHANIC_STUNNED))
4262 return SPELL_FAILED_STUNNED;
4263 break;
4265 if (!(getSpellInfo()->getAttributesExE() & ATTRIBUTESEXE_USABLE_WHILE_CONFUSED))
4266 return SPELL_FAILED_CONFUSED;
4267 break;
4269 if (!(getSpellInfo()->getAttributesExE() & ATTRIBUTESEXE_USABLE_WHILE_FEARED))
4270 return SPELL_FAILED_FLEEING;
4271 break;
4276 return SPELL_FAILED_SILENCED;
4278 return SPELL_FAILED_PACIFIED;
4279 break;
4280 default:
4281 break;
4282 }
4283 }
4284 }
4285 }
4286 else
4287 {
4288 // Spell cast is prevented by some state and the spell does not grant immunity to that state
4289 return errorMsg;
4290 }
4291 }
4292
4293 return SPELL_CAST_SUCCESS;
4294}
@ SPELL_AURA_DISPEL_IMMUNITY
@ SPELL_AURA_MOD_FEAR
@ SPELL_AURA_MOD_PACIFY
@ SPELL_AURA_MOD_SILENCE
@ SPELL_AURA_SCHOOL_IMMUNITY
@ SPELL_AURA_MECHANIC_IMMUNITY
@ SPELL_AURA_MOD_PACIFY_SILENCE
@ SPELL_AURA_MOD_CONFUSE
@ SPELL_AURA_MECHANIC_IMMUNITY_MASK
@ SPELL_AURA_MOD_STUN
@ DISPEL_ALL
@ DISPEL_MAGIC
@ DISPEL_POISON
@ DISPEL_DISEASE
@ DISPEL_CURSE
@ PREVENTION_TYPE_PACIFY
@ PREVENTION_TYPE_SILENCE
@ ATTRIBUTESEXE_USABLE_WHILE_CONFUSED
@ ATTRIBUTESEXE_USABLE_WHILE_STUNNED
@ ATTRIBUTESEXE_USABLE_WHILE_FEARED
@ ATTRIBUTESEXF_IGNORE_CASTER_STATE_AND_AURAS
@ ATTRIBUTESEX_DISPEL_AURAS_ON_IMMUNITY
@ ATTRIBUTESEX_UNAFFECTED_BY_SCHOOL_IMMUNE
@ ATTRIBUTESEXC_HIGH_PRIORITY
@ SPELL_FAILED_STUNNED
@ SPELL_FAILED_CONFUSED
@ SPELL_FAILED_SILENCED
@ SPELL_FAILED_FLEEING
@ SPELL_FAILED_PACIFIED
SpellMechanic
@ MECHANIC_FROZEN
@ MECHANIC_STUNNED
#define MOVEMENT_IMPAIRMENTS_AND_LOSS_OF_CONTROL_MASK
@ UNIT_FLAG_PACIFIED
@ UNIT_FLAG_SILENCED
@ UNIT_STATE_CONFUSED
@ UNIT_STATE_FLEEING
@ UNIT_STATE_STUNNED
uint32_t getEffectApplyAuraName(uint8_t idx) const
uint32_t getEffectMechanic(uint8_t idx) const
uint32_t getAttributesExE() const
uint32_t getPreventionType() const
uint32_t getMechanicsType() const
bool hasUnitStateFlag(uint32_t state_flag) const
Definition Unit.hpp:717
Here is the call graph for this function:
Here is the caller graph for this function:

◆ checkExplicitTarget()

SpellCastResult Spell::checkExplicitTarget ( Object target,
uint32_t  requiredTargetMask 
) const
private

Definition at line 5705 of file Spell.cpp.

5706{
5707 if (target == nullptr || !target->IsInWorld())
5709
5710 // Check if spell requires only gameobject targets
5711 if (requiredTargetMask == SPELL_TARGET_REQUIRE_GAMEOBJECT)
5712 {
5713 if (!target->isGameObject())
5715 }
5716
5717 // Check if spell requires either gameobject or item target
5718 if (requiredTargetMask == (SPELL_TARGET_REQUIRE_GAMEOBJECT | SPELL_TARGET_REQUIRE_ITEM))
5719 {
5720 if (!target->isGameObject() && !target->isItem())
5722 }
5723
5724 // Check if spell can target gameobjects
5725 if (target->isGameObject() && !m_triggeredSpell && !(requiredTargetMask & SPELL_TARGET_OBJECT_SCRIPTED) && !(requiredTargetMask & SPELL_TARGET_REQUIRE_GAMEOBJECT))
5727
5728 // Check if spell can target items
5729 if (target->isItem() && !m_triggeredSpell && !(requiredTargetMask & SPELL_TARGET_REQUIRE_ITEM))
5731
5732 // Check if spell can target friendly unit
5733 if (requiredTargetMask & SPELL_TARGET_REQUIRE_FRIENDLY && !m_caster->isFriendlyTo(target))
5735
5736 // Check if spell can target attackable unit
5737 if (requiredTargetMask & SPELL_TARGET_REQUIRE_ATTACKABLE && !(requiredTargetMask & SPELL_TARGET_AREA_SELF && m_caster == target) && !m_caster->isValidTarget(target, getSpellInfo()))
5739
5740 if (requiredTargetMask & SPELL_TARGET_OBJECT_TARCLASS)
5741 {
5742 const auto* const originalTarget = m_caster->getWorldMapObject(m_targets.getUnitTargetGuid());
5743 if (originalTarget == nullptr)
5745 if (originalTarget->isPlayer() != target->isPlayer())
5747 if ((originalTarget->isPlayer() && target->isPlayer() && static_cast<Player const*>(originalTarget)->getClass() != static_cast<Player const*>(target)->getClass()))
5749 }
5750
5751 // Check if spell requires pet target
5752 if (requiredTargetMask & SPELL_TARGET_OBJECT_CURPET && !target->isPet())
5753 {
5754 // If spell also requires item target, check for item
5755 if (requiredTargetMask & SPELL_TARGET_REQUIRE_ITEM)
5756 {
5757 if (!target->isItem())
5759 }
5760 else
5761 {
5763 }
5764 }
5765
5766 // Area spells cannot target totems or dead units unless spell caster is the target
5767 if (m_caster != target &&
5768 ((target->isCreatureOrPlayer() && !static_cast<Unit const*>(target)->isAlive()) || (target->isCreature() && target->isTotem()))
5771
5772 return SPELL_CAST_SUCCESS;
5773}
@ SPELL_TARGET_OBJECT_SCRIPTED
Definition SpellTarget.h:30
@ SPELL_TARGET_OBJECT_CURPET
Definition SpellTarget.h:32
@ SPELL_TARGET_AREA_CONE
Definition SpellTarget.h:39
@ SPELL_TARGET_REQUIRE_FRIENDLY
Definition SpellTarget.h:29
@ SPELL_TARGET_REQUIRE_GAMEOBJECT
Definition SpellTarget.h:26
@ SPELL_TARGET_REQUIRE_ITEM
Definition SpellTarget.h:27
@ SPELL_TARGET_OBJECT_TARCLASS
Definition SpellTarget.h:36
#define const
Definition zconf.h:196
bool isValidTarget(Object *target, SpellInfo const *bySpell=nullptr)
Definition Object.cpp:4073
Here is the call graph for this function:
Here is the caller graph for this function:

◆ checkItems()

SpellCastResult Spell::checkItems ( uint32_t parameter1,
uint32_t parameter2 
) const
private

Definition at line 3295 of file Spell.cpp.

3296{
3297 // Skip for non-player casters
3298 if (p_caster == nullptr)
3299 return SPELL_CAST_SUCCESS;
3300
3301 // If spell is casted from an enchant scroll
3302 auto scrollItem = false;
3303 // If spell is casted on an armor vellum or on a weapon vellum
3304 auto vellumTarget = false;
3305
3306 // Casted by an item
3307 if (i_caster != nullptr)
3308 {
3311
3312 // Check if the item is in trade window
3315
3316 const auto itemProperties = i_caster->getItemProperties();
3317 if (itemProperties == nullptr)
3319
3320 // Check if the item is an enchant scroll
3321 if (itemProperties->Flags & ITEM_FLAG_ENCHANT_SCROLL)
3322 scrollItem = true;
3323
3324 // Check if the item has any charges left
3325 for (uint8_t i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
3326 {
3327 if (itemProperties->Spells[i].Charges > 0 && i_caster->getSpellCharges(i) == 0)
3329 }
3330
3331#if VERSION_STRING < WotLK
3332 // Check zone
3333 if (itemProperties->ZoneNameID > 0 && itemProperties->ZoneNameID != p_caster->getZoneId())
3334 return SPELL_FAILED_NOT_HERE;
3335 // Check map
3336 if (itemProperties->MapID > 0 && itemProperties->MapID != p_caster->GetMapId())
3337 return SPELL_FAILED_NOT_HERE;
3338#else
3339 // Check zone
3340 if (itemProperties->ZoneNameID > 0 && itemProperties->ZoneNameID != p_caster->getZoneId())
3341 return SPELL_FAILED_INCORRECT_AREA;
3342 // Check map
3343 if (itemProperties->MapID > 0 && itemProperties->MapID != p_caster->GetMapId())
3344 return SPELL_FAILED_INCORRECT_AREA;
3345#endif
3346
3347 if (getSpellInfo()->getAuraInterruptFlags() & AURA_INTERRUPT_ON_STAND_UP)
3348 {
3350 {
3353 }
3354 else if (p_caster->isMounted())
3355 {
3357 }
3358 }
3359
3360 // Check health and power for consumables (potions, healthstones, mana items etc)
3361 if (itemProperties->Class == ITEM_CLASS_CONSUMABLE)
3362 {
3363 const auto targetUnit = p_caster->getWorldMapUnit(m_targets.getUnitTargetGuid());
3364 if (targetUnit != nullptr)
3365 {
3366 SpellCastResult errorMessage = SPELL_CAST_SUCCESS;
3367 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
3368 {
3369 // Pet related effects are handled later
3370 if (getSpellInfo()->getEffectImplicitTargetA(i) == EFF_TARGET_PET)
3371 continue;
3372
3373 // +HP items
3374 if (getSpellInfo()->getEffect(i) == SPELL_EFFECT_HEAL)
3375 {
3376 // Check if target has full health
3377 if (targetUnit->getHealthPct() == 100)
3378 {
3380 continue;
3381 }
3382 else
3383 {
3384 errorMessage = SPELL_CAST_SUCCESS;
3385 break;
3386 }
3387 }
3388
3389 // +Mana/Power items
3390 if (getSpellInfo()->getEffect(i) == SPELL_EFFECT_ENERGIZE)
3391 {
3392 // Check if the spell has valid power type
3393 if (getSpellInfo()->getEffectMiscValue(i) < 0 || getSpellInfo()->getEffectMiscValue(i) >= TOTAL_PLAYER_POWER_TYPES)
3394 {
3396 continue;
3397 }
3398
3399 // Check if target has full powers
3400 const auto powerType = static_cast<PowerType>(getSpellInfo()->getEffectMiscValue(i));
3401 if (targetUnit->getPowerPct(powerType) == 100)
3402 {
3403#if VERSION_STRING == Classic
3405#else
3406 errorMessage = powerType == POWER_TYPE_MANA ? SPELL_FAILED_ALREADY_AT_FULL_MANA : SPELL_FAILED_ALREADY_AT_FULL_POWER;
3407#endif
3408 continue;
3409 }
3410 else
3411 {
3412 errorMessage = SPELL_CAST_SUCCESS;
3413 break;
3414 }
3415 }
3416 }
3417
3418 if (errorMessage != SPELL_CAST_SUCCESS)
3419 return errorMessage;
3420 }
3421 }
3422
3423 // Check if item can be used while in shapeshift form
3425 {
3426 const auto shapeShift = sSpellShapeshiftFormStore.lookupEntry(p_caster->getShapeShiftForm());
3427 if (shapeShift != nullptr && !(shapeShift->Flags & 1))
3428 {
3431 }
3432 }
3433 }
3434
3435 // Casted on an item
3436 if (m_targets.getItemTargetGuid() > 0)
3437 {
3438 Item* targetItem = nullptr;
3439 // Check if the targeted item is in the trade window
3440 if (m_targets.isTradeItem())
3441 {
3442 // Only enchanting and lockpicking effects can be used in trade window
3446 {
3449
3450 if (p_caster->getTradeTarget() != nullptr)
3452 }
3453 else
3454 {
3456 }
3457 }
3458 else
3459 {
3461 }
3462
3463 if (targetItem == nullptr)
3465
3466 // Check explicit item target
3467 const auto targetCheck = checkExplicitTarget(targetItem, getSpellInfo()->getRequiredTargetMask(true));
3468 if (targetCheck != SPELL_CAST_SUCCESS)
3469 return targetCheck;
3470
3471 if (!targetItem->fitsToSpellRequirements(getSpellInfo()))
3473
3474 // Prevent exploiting (enchanting broken items and stacking them)
3475 if (targetItem->getDurability() == 0 && targetItem->getMaxDurability() != 0)
3477
3478 if ((getSpellInfo()->getEquippedItemClass() == ITEM_CLASS_ARMOR && targetItem->getItemProperties()->Class == ITEM_CLASS_TRADEGOODS && targetItem->getItemProperties()->SubClass == ITEM_SUBCLASS_ARMOR_ENCHANTMENT) ||
3479 (getSpellInfo()->getEquippedItemClass() == ITEM_CLASS_WEAPON && targetItem->getItemProperties()->Class == ITEM_CLASS_TRADEGOODS && targetItem->getItemProperties()->SubClass == ITEM_SUBCLASS_WEAPON_ENCHANTMENT))
3480 vellumTarget = true;
3481 }
3482 // Spell requires an item to be equipped
3483 else if (m_targets.getItemTargetGuid() == 0 && getSpellInfo()->getEquippedItemClass() >= 0)
3484 {
3485 auto hasItemWithProperType = false;
3486 switch (getSpellInfo()->getEquippedItemClass())
3487 {
3488 // Spell requires a melee weapon or a ranged weapon
3489 case ITEM_CLASS_WEAPON:
3490 {
3492 {
3493 const auto inventoryItem = p_caster->getItemInterface()->GetInventoryItem(i);
3494 if (inventoryItem != nullptr)
3495 {
3496 // Check if the weapon slot is disarmed
3498#if VERSION_STRING >= WotLK
3499 || (i == EQUIPMENT_SLOT_OFFHAND && p_caster->hasUnitFlags2(UNIT_FLAG2_DISARM_OFFHAND))
3500 || (i == EQUIPMENT_SLOT_RANGED && p_caster->hasUnitFlags2(UNIT_FLAG2_DISARM_RANGED))
3501#endif
3502 )
3503 continue;
3504
3505 // Check for proper item class and subclass
3506 if (inventoryItem->fitsToSpellRequirements(getSpellInfo()))
3507 {
3508 hasItemWithProperType = true;
3509 break;
3510 }
3511 }
3512 }
3513 } break;
3514 // Spell requires an armor piece (like shield)
3515 case ITEM_CLASS_ARMOR:
3516 {
3517 // Check first if spell requires a shield equipped
3518 Item* inventoryItem;
3519 if (getSpellInfo()->getEquippedItemSubClass() & (1 << ITEM_SUBCLASS_ARMOR_SHIELD))
3520 {
3522 if (inventoryItem != nullptr)
3523 {
3524#if VERSION_STRING >= WotLK
3525 // Check for offhand disarm
3526 if (!p_caster->hasUnitFlags2(UNIT_FLAG2_DISARM_OFFHAND))
3527#endif
3528 {
3529 // Check for proper item class and subclass
3530 if (inventoryItem->fitsToSpellRequirements(getSpellInfo()))
3531 {
3532 hasItemWithProperType = true;
3533 break;
3534 }
3535 }
3536 }
3537 }
3538
3539 // Check for other armor pieces
3541 {
3542 inventoryItem = p_caster->getItemInterface()->GetInventoryItem(i);
3543 if (inventoryItem != nullptr)
3544 {
3545 // Check for proper item class and subclass
3546 if (inventoryItem->fitsToSpellRequirements(getSpellInfo()))
3547 {
3548 hasItemWithProperType = true;
3549 break;
3550 }
3551 }
3552 }
3553
3554 // No need to check further if found already
3555 if (hasItemWithProperType)
3556 break;
3557
3558 // Ranged slot can have an item classified as armor (no need to check for disarm in these cases)
3560 if (inventoryItem != nullptr)
3561 {
3562 // Check for proper item class and subclass
3563 if (inventoryItem->fitsToSpellRequirements(getSpellInfo()))
3564 {
3565 hasItemWithProperType = true;
3566 break;
3567 }
3568 }
3569 } break;
3570 default:
3571 break;
3572 }
3573
3574 // These triggered learn spell effects shouldn't fail here
3575 if (m_triggeredSpell)
3576 {
3577 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
3578 {
3579 const auto eff = getSpellInfo()->getEffect(i);
3580 if (eff == SPELL_EFFECT_NULL)
3581 continue;
3582
3584 {
3585 hasItemWithProperType = true;
3586 break;
3587 }
3588 }
3589 }
3590
3591 if (!hasItemWithProperType)
3592 {
3593 *parameter1 = static_cast<uint32_t>(getSpellInfo()->getEquippedItemClass());
3594 *parameter2 = static_cast<uint32_t>(getSpellInfo()->getEquippedItemSubClass());
3596 }
3597
3598 // Temporary helper lambda
3599 const auto hasEquippableWeapon = [&](Item const* weapon) -> bool
3600 {
3601 if (weapon == nullptr)
3602 return false;
3603 if (weapon->getItemProperties()->MaxDurability > 0 && weapon->getDurability() == 0)
3604 return false;
3605 return weapon->fitsToSpellRequirements(getSpellInfo());
3606 };
3607
3608 // Check if spell explicitly requires a main hand weapon
3610 {
3613 }
3614
3615 // Check if spell explicitly requires an offhand weapon
3617 {
3620 }
3621 }
3622
3623 // Check if the spell requires any reagents or tools (skip enchant scrolls)
3625 {
3626#if VERSION_STRING == Classic
3627 auto checkForReagents = true;
3628#else
3629 // Spells with ATTRIBUTESEXE_REAGENT_REMOVAL attribute won't take reagents if player has UNIT_FLAG_NO_REAGANT_COST flag
3630 auto checkForReagents = !(getSpellInfo()->getAttributesExE() & ATTRIBUTESEXE_REAGENT_REMOVAL && p_caster->hasUnitFlags(UNIT_FLAG_NO_REAGANT_COST));
3631#endif
3632 if (checkForReagents)
3633 {
3634#if VERSION_STRING >= WotLK
3635 // Check for spells which remove the reagent cost for a spell
3636 // e.g. Glyph of Slow Fall or Glyph of Levitate
3637 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
3638 {
3639 if (getSpellInfo()->getSpellFamilyFlags(i) == 0)
3640 continue;
3642 {
3643 checkForReagents = false;
3644 break;
3645 }
3646 }
3647#endif
3648 }
3649 // Reagents will always be checked for items in trade window
3650 else if (m_targets.getItemTargetGuid() != 0 && m_targets.isTradeItem())
3651 {
3652 checkForReagents = true;
3653 }
3654
3655 if (checkForReagents)
3656 {
3657 for (uint8_t i = 0; i < MAX_SPELL_REAGENTS; ++i)
3658 {
3659 if (getSpellInfo()->getReagent(i) == 0)
3660 continue;
3661
3662 const auto itemId = static_cast<uint32_t>(getSpellInfo()->getReagent(i));
3663 auto itemCount = getSpellInfo()->getReagentCount(i);
3664
3665 // Some spells include the used item as one of the reagents
3666 // So in these cases itemCount must be incremented by one
3667 // e.g. item id 24502 requires 7 items but DBC data requires only 6, because the one missing item is the caster
3668 if (i_caster != nullptr && i_caster->getEntry() == itemId)
3669 {
3670 const auto itemProperties = i_caster->getItemProperties();
3671 for (uint8_t x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x)
3672 {
3673 if (itemProperties->Spells[x].Id == 0)
3674 continue;
3675 if (itemProperties->Spells[x].Charges == -1 && i_caster->getSpellCharges(x) <= 1)
3676 {
3677 ++itemCount;
3678 break;
3679 }
3680 }
3681 }
3682
3683 if (!p_caster->hasItem(itemId, itemCount))
3684 {
3685#if VERSION_STRING == Classic
3686 //\ todo: figure out correct error message
3688#else
3689 *parameter1 = itemId;
3690 return SPELL_FAILED_REAGENTS;
3691#endif
3692 }
3693 }
3694 }
3695
3696 // Check for totem items
3697 for (uint8_t i = 0; i < MAX_SPELL_TOTEMS; ++i)
3698 {
3699 if (getSpellInfo()->getTotem(i) != 0)
3700 {
3701 if (!p_caster->hasItem(getSpellInfo()->getTotem(i)))
3702 {
3703#if VERSION_STRING == Classic
3704 //\ todo: figure out correct error message
3706#else
3707 *parameter1 = getSpellInfo()->getTotem(i);
3708 return SPELL_FAILED_TOTEMS;
3709#endif
3710 }
3711 }
3712 }
3713
3714#if VERSION_STRING >= TBC
3715 // Check for totem category items
3716 for (uint8_t i = 0; i < MAX_SPELL_TOTEM_CATEGORIES; ++i)
3717 {
3718 if (getSpellInfo()->getTotemCategory(i) != 0 && !p_caster->getItemInterface()->hasItemForTotemCategory(getSpellInfo()->getTotemCategory(i)))
3719 {
3720 *parameter1 = getSpellInfo()->getTotemCategory(i);
3721 return SPELL_FAILED_TOTEM_CATEGORY;
3722 }
3723 }
3724#endif
3725 }
3726
3727 // Special checks for different spell effects
3728 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
3729 {
3730 if (getSpellInfo()->getEffect(i) == 0)
3731 continue;
3732
3733 switch (getSpellInfo()->getEffect(i))
3734 {
3736#if VERSION_STRING >= WotLK
3738#endif
3739 if (getSpellInfo()->getEffectItemType(i) != 0)
3740 {
3741 const auto itemProperties = sMySQLStore.getItemProperties(getSpellInfo()->getEffectItemType(i));
3742 if (itemProperties == nullptr)
3743 {
3744 sLogger.failure("Spell::checkItems: Spell entry {} has unknown item id ({}) in SPELL_EFFECT_CREATE_ITEM effect", getSpellInfo()->getId(), getSpellInfo()->getEffectItemType(i));
3745 return SPELL_FAILED_ERROR;
3746 }
3747
3748 // Check if player has any free slots in the inventory
3749 if (p_caster->getItemInterface()->CalculateFreeSlots(itemProperties) == 0)
3750 {
3753 }
3754
3755 // Check other limitations
3756 const auto itemErrorMessage = p_caster->getItemInterface()->CanReceiveItem(itemProperties, 1);
3757 if (itemErrorMessage != INV_ERR_OK)
3758 {
3759 p_caster->getItemInterface()->buildInventoryChangeError(nullptr, nullptr, itemErrorMessage, getSpellInfo()->getEffectItemType(i));
3761 }
3762 } break;
3764 {
3765 // Check only for vellums here, normal checks are done in the next case
3766 if (getSpellInfo()->getEffectItemType(i) != 0 && m_targets.getItemTargetGuid() != 0 && vellumTarget)
3767 {
3768 // Player can only enchant their own vellums
3769 if (m_targets.isTradeItem())
3771 // Scrolls (enchanted vellums) cannot be enchanted into another vellum (duping)
3772 if (scrollItem)
3774
3775 const auto vellumItem = p_caster->getItemInterface()->GetItemByGUID(m_targets.getItemTargetGuid());
3776 if (vellumItem == nullptr)
3778 // Check if vellum is appropriate target for the enchant
3779 if (getSpellInfo()->getBaseLevel() > vellumItem->getItemProperties()->ItemLevel)
3780 return SPELL_FAILED_LOWLEVEL;
3781
3782 const auto itemProperties = sMySQLStore.getItemProperties(getSpellInfo()->getEffectItemType(i));
3783 if (itemProperties == nullptr)
3784 {
3785 sLogger.failure("Spell::checkItems: Spell entry {} has unknown item id ({}) in SPELL_EFFECT_ENCHANT_ITEM effect", getSpellInfo()->getId(), getSpellInfo()->getEffectItemType(i));
3786 return SPELL_FAILED_ERROR;
3787 }
3788
3789 // Check if player has any free slots in the inventory
3790 if (p_caster->getItemInterface()->CalculateFreeSlots(itemProperties) == 0)
3791 {
3794 }
3795
3796 // Check other limitations
3797 const auto itemErrorMessage = p_caster->getItemInterface()->CanReceiveItem(itemProperties, 1);
3798 if (itemErrorMessage != INV_ERR_OK)
3799 {
3800 p_caster->getItemInterface()->buildInventoryChangeError(nullptr, nullptr, itemErrorMessage, getSpellInfo()->getEffectItemType(i));
3802 }
3803 }
3804#if VERSION_STRING >= WotLK
3805 }
3806 [[fallthrough]];
3808 {
3809#endif
3810 if (m_targets.getItemTargetGuid() == 0)
3812
3813 Item* targetItem = nullptr;
3814 if (m_targets.isTradeItem())
3815 {
3816 if (p_caster->getTradeTarget() != nullptr)
3818 }
3819 else
3820 {
3822 }
3823
3824 if (targetItem == nullptr)
3826
3827 // Check if the item's level is high enough for the enchantment
3828 if (targetItem->getItemProperties()->ItemLevel < getSpellInfo()->getBaseLevel())
3829 return SPELL_FAILED_LOWLEVEL;
3830
3831 auto hasOnUseEffect = false;
3832 const auto itemProperties = targetItem->getItemProperties();
3833 for (const auto& spell : itemProperties->Spells)
3834 {
3835 if (spell.Id == 0)
3836 continue;
3837 if (spell.Trigger == USE || spell.Trigger == APPLY_AURA_ON_PICKUP)
3838 {
3839 hasOnUseEffect = true;
3840 break;
3841 }
3842 }
3843
3844 const auto enchantEntry = sSpellItemEnchantmentStore.lookupEntry(static_cast<uint32_t>(getSpellInfo()->getEffectMiscValue(i)));
3845 if (enchantEntry == nullptr)
3846 {
3847 sLogger.failure("Spell::checkItems: Spell entry {} has no valid enchantment ({})", getSpellInfo()->getId(), getSpellInfo()->getEffectMiscValue(i));
3848 return SPELL_FAILED_ERROR;
3849 }
3850
3851 // Loop through enchantment's types
3852 for (const auto& type : enchantEntry->type)
3853 {
3854 switch (type)
3855 {
3857 // Check if the item already has a 'on use' enchantment
3858 if (hasOnUseEffect)
3859 {
3860#if VERSION_STRING < WotLK
3862#else
3863 return SPELL_FAILED_ON_USE_ENCHANT;
3864#endif
3865 }
3866 break;
3867#if VERSION_STRING >= WotLK
3869 // Check if the item already has a prismatic gem slot enchanted
3870 if (targetItem->getEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT) != 0)
3872
3873 // or if the item already has the maximum amount of socket slots
3874 if (targetItem->getSocketSlotCount() >= MAX_ITEM_PROTO_SOCKETS)
3875 return SPELL_FAILED_MAX_SOCKETS;
3876 break;
3877#endif
3878 default:
3879 break;
3880 }
3881 }
3882
3883 // Check item owner in cases where enchantment makes item soulbound
3884 if (targetItem->getOwner() != p_caster)
3885 {
3886 if (enchantEntry->EnchantGroups & 0x01) // Makes item soulbound
3888 }
3889 break;
3890 }
3892 {
3893 if (m_targets.getItemTargetGuid() == 0)
3895
3896 Item const* targetItem = nullptr;
3897 if (m_targets.isTradeItem())
3898 {
3899 if (p_caster->getTradeTarget() != nullptr)
3901 }
3902 else
3903 {
3905 }
3906
3907 if (targetItem == nullptr)
3909
3910 const auto enchantmentEntry = sSpellItemEnchantmentStore.lookupEntry(static_cast<uint32_t>(getSpellInfo()->getEffectMiscValue(i)));
3911 if (enchantmentEntry == nullptr)
3912 {
3913 sLogger.failure("Spell::checkItems: Spell entry {} has no valid enchantment ({})", getSpellInfo()->getId(), getSpellInfo()->getEffectMiscValue(i));
3914 return SPELL_FAILED_ERROR;
3915 }
3916
3917 // Check item owner in cases where enchantment makes item soulbound
3918 if (targetItem->getOwner() != p_caster)
3919 {
3920 if (enchantmentEntry->EnchantGroups & 0x01) // Makes item soulbound
3922 }
3923 break;
3924 }
3926 {
3927 if (m_targets.getItemTargetGuid() == 0)
3929 // Check if the item target is in a trade window
3930 if (m_targets.isTradeItem())
3932
3933 const auto targetItem = p_caster->getItemInterface()->GetItemByGUID(m_targets.getItemTargetGuid());
3934 if (targetItem == nullptr)
3936
3937 const auto itemProperties = targetItem->getItemProperties();
3938 // Only armor and weapon items can be disenchanted
3939 if (itemProperties->Class != ITEM_CLASS_ARMOR && itemProperties->Class != ITEM_CLASS_WEAPON)
3941 // Only items with uncommon, rare and epic quality can be disenchanted
3942 if (itemProperties->Quality > ITEM_QUALITY_EPIC_PURPLE || itemProperties->Quality < ITEM_QUALITY_UNCOMMON_GREEN)
3944 // Some items are not disenchantable
3945 if (itemProperties->DisenchantReqSkill <= 0)
3947#if VERSION_STRING >= TBC
3948 // As of patch 2.0.1 disenchanting an item requires minimum skill level
3949 if (static_cast<uint32_t>(itemProperties->DisenchantReqSkill) > p_caster->getSkillLineCurrent(SKILL_ENCHANTING))
3950 return SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL;
3951#endif
3952 // TODO: check does the item even have disenchant loot
3953 break;
3954 }
3955#if VERSION_STRING >= TBC
3957 {
3958 if (m_targets.getItemTargetGuid() == 0)
3960 // Check if the item target is in a trade window
3961 if (m_targets.isTradeItem())
3963
3964 const auto targetItem = p_caster->getItemInterface()->GetItemByGUID(m_targets.getItemTargetGuid());
3965 if (targetItem == nullptr)
3967
3968 const auto itemProperties = targetItem->getItemProperties();
3969 // Check if the item is prospectable
3970 if (!(itemProperties->Flags & ITEM_FLAG_PROSPECTABLE))
3972 // Check if player has enough skill in Jewelcrafting
3973 if (itemProperties->RequiredSkillRank > p_caster->getSkillLineCurrent(SKILL_JEWELCRAFTING))
3974 {
3975 *parameter1 = itemProperties->RequiredSkill;
3976 *parameter2 = itemProperties->RequiredSkillRank;
3978 }
3979 // Check if player has enough ores for prospecting
3980 if (!p_caster->hasItem(targetItem->getEntry(), 5))
3981 {
3982 *parameter1 = targetItem->getEntry();
3983 *parameter2 = 5;
3984#if VERSION_STRING == TBC
3985 return SPELL_FAILED_PROSPECT_NEED_MORE;
3986#else
3987 return SPELL_FAILED_NEED_MORE_ITEMS;
3988#endif
3989 }
3990
3991 // TODO: check does the item even have prospecting loot
3992 break;
3993 }
3994#endif
3995#if VERSION_STRING >= WotLK
3997 {
3998 if (m_targets.getItemTargetGuid() == 0)
4000 // Check if the item target is in a trade window
4001 if (m_targets.isTradeItem())
4003
4004 const auto targetItem = p_caster->getItemInterface()->GetItemByGUID(m_targets.getItemTargetGuid());
4005 if (targetItem == nullptr)
4007
4008 const auto itemProperties = targetItem->getItemProperties();
4009 // Check if the item is millable
4010 if (!(itemProperties->Flags & ITEM_FLAG_MILLABLE))
4011 return SPELL_FAILED_CANT_BE_MILLED;
4012 // Check if player has enough skill in Inscription
4013 if (itemProperties->RequiredSkillRank > p_caster->getSkillLineCurrent(SKILL_INSCRIPTION))
4014 {
4015 *parameter1 = itemProperties->RequiredSkill;
4016 *parameter2 = itemProperties->RequiredSkillRank;
4018 }
4019 if (!p_caster->hasItem(targetItem->getEntry(), 5))
4020 {
4021 *parameter1 = targetItem->getEntry();
4022 *parameter2 = 5;
4023 return SPELL_FAILED_NEED_MORE_ITEMS;
4024 }
4025
4026 // TODO: check does the item even have milling loot
4027 break;
4028 }
4029#endif
4032 {
4033 // Check if spell is not ranged type
4034 if (getSpellInfo()->getDmgClass() != SPELL_DMG_TYPE_RANGED)
4035 break;
4036
4037 const auto rangedWeapon = p_caster->getItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_RANGED);
4038 if (rangedWeapon == nullptr || !rangedWeapon->isWeapon())
4040 // Check if the item has any durability left
4041 if (rangedWeapon->getMaxDurability() > 0 && rangedWeapon->getDurability() == 0)
4043
4044#if VERSION_STRING <= WotLK
4045 // Check for ammunitation
4046 switch (rangedWeapon->getItemProperties()->SubClass)
4047 {
4049 // In classic throwing weapons use stack count
4050 // In TBC throwing weapons use durability
4051 // In Wotlk+ throwing weapons use neither
4052#if VERSION_STRING == Classic
4053 if (p_caster->getItemInterface()->GetItemCount(rangedWeapon->getEntry()) == 0)
4054 return SPELL_FAILED_NO_AMMO;
4055#elif VERSION_STRING == TBC
4056 if (rangedWeapon->getDurability() == 0)
4057 return SPELL_FAILED_NO_AMMO;
4058#endif
4059 break;
4060 // Check ammo for ranged weapons
4064 {
4065 // Thori'dal, the Stars' Fury has a dummy aura which makes it generate magical arrows
4066 // iirc the only item with this kind of effect?
4068 break;
4069 const auto ammoId = p_caster->getAmmoId();
4070 if (ammoId == 0)
4072
4073 const auto ammoProperties = sMySQLStore.getItemProperties(ammoId);
4074 if (ammoProperties == nullptr)
4076 if (ammoProperties->Class != ITEM_CLASS_PROJECTILE)
4078 if (ammoProperties->RequiredLevel > p_caster->getLevel())
4080
4081 // Check for correct projectile type
4082 if (rangedWeapon->getItemProperties()->SubClass == ITEM_SUBCLASS_WEAPON_GUN)
4083 {
4084 if (ammoProperties->SubClass != ITEM_SUBCLASS_PROJECTILE_BULLET)
4086 }
4087 else
4088 {
4089 if (ammoProperties->SubClass != ITEM_SUBCLASS_PROJECTILE_ARROW)
4091 }
4092
4093 // Check if player is out of ammos
4094 if (!p_caster->hasItem(ammoId))
4095 {
4096 p_caster->setAmmoId(0);
4097 return SPELL_FAILED_NO_AMMO;
4098 }
4099 } break;
4100 default:
4101 break;
4102 }
4103#endif
4104 break;
4105 }
4106 default:
4107 break;
4108 }
4109 }
4110
4111 return SPELL_CAST_SUCCESS;
4112}
@ APPLY_AURA_ON_PICKUP
@ ITEM_QUALITY_EPIC_PURPLE
@ ITEM_QUALITY_UNCOMMON_GREEN
@ ITEM_FLAG_ENCHANT_SCROLL
@ ITEM_FLAG_PROSPECTABLE
@ ITEM_FLAG_MILLABLE
@ ITEM_FLAG_SHAPESHIFT_OK
@ ITEM_CLASS_PROJECTILE
@ ITEM_CLASS_ARMOR
@ ITEM_CLASS_TRADEGOODS
@ ITEM_CLASS_WEAPON
@ EQUIPMENT_SLOT_HEAD
@ EQUIPMENT_SLOT_OFFHAND
@ EQUIPMENT_SLOT_RANGED
@ ITEM_SUBCLASS_WEAPON_CROSSBOW
@ ITEM_SUBCLASS_WEAPON_GUN
@ ITEM_SUBCLASS_ARMOR_ENCHANTMENT
@ ITEM_SUBCLASS_PROJECTILE_ARROW
@ ITEM_SUBCLASS_ARMOR_SHIELD
@ ITEM_SUBCLASS_WEAPON_BOW
@ ITEM_SUBCLASS_WEAPON_THROWN
@ ITEM_SUBCLASS_PROJECTILE_BULLET
@ ITEM_SUBCLASS_WEAPON_ENCHANTMENT
@ INV_ERR_OK
@ INV_ERR_CANT_DO_IN_COMBAT
@ INV_ERR_INVENTORY_FULL
@ PRISMATIC_ENCHANTMENT_SLOT
@ ITEM_ENCHANTMENT_TYPE_USE_SPELL
@ ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET
#define MAX_ITEM_PROTO_SOCKETS
#define sMySQLStore
PowerType
Definition PowerType.hpp:11
@ TOTAL_PLAYER_POWER_TYPES
Definition PowerType.hpp:38
@ SKILL_ENCHANTING
Definition Skill.hpp:123
@ SKILL_JEWELCRAFTING
Definition Skill.hpp:166
@ ATTRIBUTESEXE_REAGENT_REMOVAL
@ ATTRIBUTESEXB_ENCHANT_OWN_ONLY
@ ATTRIBUTESEXC_REQUIRES_OFFHAND_WEAPON
@ ATTRIBUTESEXC_REQUIRES_MAIN_HAND_WEAPON
@ SPELL_EFFECT_DISENCHANT
@ SPELL_EFFECT_PROSPECTING
@ SPELL_EFFECT_PROFICIENCY
@ SPELL_EFFECT_ENCHANT_ITEM
@ SPELL_EFFECT_WEAPON_DAMAGE
@ SPELL_EFFECT_ADD_SOCKET
@ SPELL_EFFECT_MILLING
@ SPELL_EFFECT_WEAPON
@ SPELL_EFFECT_BLOCK
@ SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
@ SPELL_EFFECT_ENERGIZE
@ SPELL_EFFECT_CREATE_ITEM2
@ SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
@ SPELL_EFFECT_CREATE_ITEM
@ SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND
@ SPELL_FAILED_EQUIPPED_ITEM_CLASS
@ SPELL_FAILED_MIN_SKILL
@ SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED
@ SPELL_FAILED_ALREADY_AT_FULL_POWER
@ SPELL_FAILED_NOT_TRADEABLE
@ SPELL_FAILED_ITEM_NOT_READY
@ SPELL_FAILED_NO_CHARGES_REMAIN
@ SPELL_FAILED_NEED_AMMO
@ SPELL_FAILED_NO_AMMO
@ SPELL_FAILED_EQUIPPED_ITEM
@ SPELL_FAILED_ALREADY_AT_FULL_HEALTH
@ SPELL_FAILED_ERROR
@ SPELL_FAILED_ITEM_ALREADY_ENCHANTED
@ SPELL_FAILED_CANT_BE_DISENCHANTED
@ SPELL_FAILED_NOT_WHILE_TRADING
@ SPELL_FAILED_CANT_BE_PROSPECTED
@ SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND
@ UNIT_FLAG2_DISARM_OFFHAND
@ UNIT_FLAG2_DISARM_RANGED
static constexpr uint8_t MAX_SPELL_REAGENTS
static constexpr uint8_t MAX_SPELL_TOTEM_CATEGORIES
static constexpr uint8_t MAX_SPELL_TOTEMS
SERVER_DECL WDB::WDBContainer< WDB::Structures::SpellShapeshiftFormEntry > sSpellShapeshiftFormStore
SERVER_DECL WDB::WDBContainer< WDB::Structures::SpellItemEnchantmentEntry > sSpellItemEnchantmentStore
Item * GetInventoryItem(int16_t slot)
Gets a item from Inventory.
int8_t CanReceiveItem(ItemProperties const *item, uint32_t amount)
Checks if player can receive the item.
void buildInventoryChangeError(Item const *srcItem, Item const *dstItem, uint8_t inventoryError, uint32_t srcItemId=0)
uint32_t CalculateFreeSlots(ItemProperties const *proto)
Calculates inventory free slots, bag inventory slots not included.
bool hasItemForTotemCategory(uint32_t totemCategory)
uint32_t getDurability() const
Definition Item.cpp:216
uint32_t getMaxDurability() const
Definition Item.cpp:219
int32_t getSpellCharges(uint8_t index) const
Definition Item.cpp:166
uint32_t getEnchantmentId(uint8_t index) const
Definition Item.cpp:193
bool fitsToSpellRequirements(SpellInfo const *spellInfo) const
Definition Item.cpp:957
uint8_t getSocketSlotCount(bool includePrismatic=true) const
Definition Item.cpp:824
uint32_t getNoReagentCost(uint8_t index) const
Definition Player.cpp:1303
bool hasItem(uint32_t itemId, uint32_t amount=1, bool checkBankAlso=false) const
Definition Player.cpp:6641
bool m_requiresNoAmmo
Definition Player.hpp:2043
int32_t getEquippedItemClass() const
uint32_t getSpellFamilyFlags(uint8_t idx) const
int32_t getEquippedItemSubClass() const
uint32_t getReagentCount(uint8_t idx) const
uint32_t getTotem(uint8_t idx) const
int32_t getReagent(uint8_t idx) const
Item * getTradeItem(TradeSlots slot) const
Definition TradeData.cpp:36
bool hasPlayerOrTraderItemInTrade(uint64_t itemGuid) const
Definition TradeData.cpp:52
type
Definition core.h:573
signed short int16_t
Here is the caller graph for this function:

◆ checkPower()

SpellCastResult Spell::checkPower ( )

Definition at line 3250 of file Spell.cpp.

3251{
3252 if (m_powerCost == 0)
3253 return SPELL_CAST_SUCCESS;
3254
3255 if (p_caster != nullptr && p_caster->m_cheats.hasPowerCheat)
3256 return SPELL_CAST_SUCCESS;
3257
3258 // Check if caster has enough health points if health is used for power
3259 if (getSpellInfo()->getPowerType() == POWER_TYPE_HEALTH)
3260 {
3261 if (u_caster != nullptr)
3262 {
3263 if (u_caster->getHealth() <= m_powerCost)
3264 return SPELL_FAILED_FIZZLE;
3265 }
3266
3267 // No need to do any further checking
3268 return SPELL_CAST_SUCCESS;
3269 }
3270
3271 // Invalid power types
3272 if (!getSpellInfo()->hasValidPowerType())
3273 {
3274 sLogger.failure("Spell::checkPower : Unknown power type {} for spell id {}", getSpellInfo()->getPowerType(), getSpellInfo()->getId());
3275 return SPELL_FAILED_ERROR;
3276 }
3277
3278#if VERSION_STRING >= WotLK
3279 // Check runes for spells which have runes in power type
3280 if (getSpellInfo()->getPowerType() == POWER_TYPE_RUNES)
3281 {
3282 const auto runeResult = checkRunes(false);
3283 if (runeResult != SPELL_CAST_SUCCESS)
3284 return runeResult;
3285 }
3286#endif
3287
3288 // Normal case
3289 if (u_caster != nullptr && u_caster->getPower(getSpellInfo()->getPowerType()) < m_powerCost)
3290 return SPELL_FAILED_NO_POWER;
3291
3292 return SPELL_CAST_SUCCESS;
3293}
@ POWER_TYPE_HEALTH
Definition PowerType.hpp:12
@ SPELL_FAILED_NO_POWER
@ SPELL_FAILED_FIZZLE
PlayerCheat m_cheats
Definition Player.hpp:1090
SpellCastResult checkRunes(bool takeRunes)
Definition Spell.cpp:4433
uint32_t getHealth() const
Definition Unit.cpp:481
uint32_t getPower(PowerType type) const
Definition Unit.cpp:516
Here is the call graph for this function:
Here is the caller graph for this function:

◆ checkRange()

SpellCastResult Spell::checkRange ( const bool  secondCheck)
private

\ todo: Needs retesting after movement system has been rewritten

Definition at line 4296 of file Spell.cpp.

4297{
4298 const auto rangeEntry = sSpellRangeStore.lookupEntry(getSpellInfo()->getRangeIndex());
4299 if (rangeEntry == nullptr)
4300 return SPELL_CAST_SUCCESS;
4301
4302 // Players can activate "on next attack" abilities before being at melee range
4303 if (!secondCheck && getSpellInfo()->isOnNextMeleeAttack())
4304 return SPELL_CAST_SUCCESS;
4305
4307
4308 // Self cast spells don't need range check
4309 if (getSpellInfo()->getRangeIndex() == 1 || targetUnit == m_caster)
4310 return SPELL_CAST_SUCCESS;
4311
4312 if (u_caster != nullptr)
4313 {
4314 // If pet is the effect target, check range to pet
4315 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
4316 {
4317 if (getSpellInfo()->getEffectImplicitTargetA(i) != EFF_TARGET_PET)
4318 continue;
4319
4320 if (u_caster->getPet() != nullptr)
4321 {
4322 targetUnit = u_caster->getPet();
4323 break;
4324 }
4325 }
4326 }
4327
4328 float_t minRange = 0.0f, maxRange = 0.0f, rangeMod = 0.0f;
4329 if (rangeEntry->range_type & SPELL_RANGE_TYPE_MASK_MELEE)
4330 {
4331 if (u_caster != nullptr)
4332 {
4333 // Use caster's combat reach if target is not found
4334 const float_t combatReach = targetUnit != nullptr ? targetUnit->getCombatReach() : u_caster->getCombatReach();
4335 // Caster's combat reach + 1.333... + target's (or caster's again) combat reach
4336 rangeMod = std::max(5.0f, u_caster->getCombatReach() + (4.0f / 3.0f) + combatReach);
4337 }
4338 }
4339 else
4340 {
4341 if (u_caster != nullptr && rangeEntry->range_type & SPELL_RANGE_TYPE_MASK_RANGED)
4342 {
4343 // Use caster's combat reach if target is not found
4344 const float_t combatReach = targetUnit != nullptr ? targetUnit->getCombatReach() : u_caster->getCombatReach();
4345 // Caster's combat reach + 1.33f + target's (or caster's again) combat reach
4346 minRange = std::max(5.0f, u_caster->getCombatReach() + (4.0f / 3.0f) + combatReach);
4347 }
4348
4349 // Get minimum range
4350#if VERSION_STRING < WotLK
4351 minRange += rangeEntry->minRange;
4352#else
4353 if (targetUnit == nullptr)
4354 minRange += rangeEntry->minRange;
4355 else
4356 minRange += m_caster->isFriendlyTo(targetUnit) ? rangeEntry->minRangeFriendly : rangeEntry->minRange;
4357#endif
4358
4359 // Get maximum range
4360#if VERSION_STRING < WotLK
4361 maxRange = rangeEntry->maxRange;
4362#else
4363 if (targetUnit == nullptr)
4364 maxRange = rangeEntry->maxRange;
4365 else
4366 maxRange = m_caster->isFriendlyTo(targetUnit) ? rangeEntry->maxRangeFriendly : rangeEntry->maxRange;
4367#endif
4368
4369 // Player, creature or corpse target
4370 if (u_caster != nullptr && (targetUnit != nullptr || m_targets.getTargetMask() & (TARGET_FLAG_CORPSE | TARGET_FLAG_CORPSE2)))
4371 {
4372 const float_t combatReach = targetUnit != nullptr ? targetUnit->getCombatReach() : u_caster->getCombatReach();
4373 rangeMod = u_caster->getCombatReach() + combatReach;
4374 if (minRange > 0.0f && !(rangeEntry->range_type & SPELL_RANGE_TYPE_MASK_RANGED))
4375 minRange += rangeMod;
4376 }
4377 }
4378
4379 // Spell leeway - Client increases spell's range if the caster is moving (walking is not accounted)
4380 ///\ todo: Needs retesting after movement system has been rewritten
4382 {
4383 // Leeway mechanic also depends on target - target also needs to be moving (again, walking is not accounted)
4384 if (targetUnit != nullptr && targetUnit->hasUnitMovementFlag(MOVEFLAG_MOVING_MASK) && !targetUnit->hasUnitMovementFlag(MOVEFLAG_WALK)
4385 && (rangeEntry->range_type & SPELL_RANGE_TYPE_MASK_MELEE || targetUnit->isPlayer()))
4386 rangeMod += 8.0f / 3.0f; // 2.6666... yards
4387 }
4388
4389 // Add range from ranged weapon to max range
4390 if (p_caster != nullptr && getSpellInfo()->getAttributes() & ATTRIBUTES_RANGED)
4391 {
4392 const auto rangedWeapon = p_caster->getItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_RANGED);
4393 if (rangedWeapon != nullptr)
4394 maxRange *= rangedWeapon->getItemProperties()->Range * 0.01f;
4395 }
4396
4397 // Add 5 yards to range check for spell landing because some spells have a delay before landing
4398 rangeMod += secondCheck ? (m_caster->isPlayer() ? 6.25f : 2.25f) : (m_caster->isPlayer() ? 1.25f : 0.0f);
4399
4400 // Apply spell modifiers to range
4401 if (u_caster != nullptr)
4403
4404 maxRange += rangeMod;
4405
4406 // Square values for range check
4407 minRange *= minRange;
4408 maxRange *= maxRange;
4409
4410 if (targetUnit != nullptr && targetUnit != m_caster)
4411 {
4412 const float_t distance = m_caster->getDistanceSq(targetUnit);
4413 if (minRange > 0.0f && distance < minRange)
4415 if (distance > maxRange)
4417 }
4418
4419 // AoE spells on targeted location
4421 {
4423 if (minRange > 0.0f && distance < minRange)
4425 if (distance > maxRange)
4427 }
4428
4429 return SPELL_CAST_SUCCESS;
4430}
@ MOVEFLAG_MOVING_MASK
@ MOVEFLAG_WALK
@ SPELL_RANGE_TYPE_MASK_RANGED
@ SPELL_RANGE_TYPE_MASK_MELEE
@ ATTRIBUTES_RANGED
@ SPELL_FAILED_TOO_CLOSE
@ SPELLMOD_RANGE
float getDistanceSq(LocationVector target) const
Definition Object.cpp:588
float getCombatReach() const
Definition Unit.cpp:1249
bool hasUnitMovementFlag(uint32_t f) const
Definition Unit.cpp:1937
Here is the call graph for this function:
Here is the caller graph for this function:

◆ checkRunes()

SpellCastResult Spell::checkRunes ( bool  takeRunes)
private

Definition at line 4433 of file Spell.cpp.

4434{
4435 // Check only for players and for spells which have rune cost
4436 if (getSpellInfo()->getRuneCostID() > 0 && p_caster != nullptr)
4437 {
4438 // Classes other than Death Knights should not cast spells which use runes
4440 return SPELL_FAILED_NO_POWER;
4441
4442 const auto spellRuneCost = sSpellRuneCostStore.lookupEntry(getSpellInfo()->getRuneCostID());
4443 if (spellRuneCost != nullptr && (spellRuneCost->bloodRuneCost > 0 || spellRuneCost->frostRuneCost > 0 || spellRuneCost->unholyRuneCost > 0))
4444 {
4445 uint32_t runeCost[3];
4446 runeCost[RUNE_BLOOD] = spellRuneCost->bloodRuneCost;
4447 runeCost[RUNE_FROST] = spellRuneCost->frostRuneCost;
4448 runeCost[RUNE_UNHOLY] = spellRuneCost->unholyRuneCost;
4449
4450 // Apply modifers
4451 for (uint8_t i = 0; i < RUNE_DEATH; ++i)
4452 {
4453 p_caster->applySpellModifiers(SPELLMOD_COST, &runeCost[i], getSpellInfo(), this);
4454 }
4455
4456 if (const auto dkPlayer = dynamic_cast<DeathKnight*>(p_caster))
4457 {
4458 // Get available runes and subtract them from the power cost
4459 // If the outcome is over zero, it means player doesn't have enough runes available
4460 auto missingRunes = dkPlayer->HasRunes(RUNE_BLOOD, runeCost[RUNE_BLOOD]) + dkPlayer->HasRunes(RUNE_FROST, runeCost[RUNE_FROST]) + dkPlayer->HasRunes(RUNE_UNHOLY, runeCost[RUNE_UNHOLY]);
4461 // If there aren't enough normal runes available, try death runes
4462 if (missingRunes > 0 && dkPlayer->HasRunes(RUNE_DEATH, missingRunes) > 0)
4463 return SPELL_FAILED_NO_POWER;
4464
4465 if (takeRunes)
4466 {
4467 missingRunes = dkPlayer->TakeRunes(RUNE_BLOOD, runeCost[RUNE_BLOOD]) + dkPlayer->TakeRunes(RUNE_FROST, runeCost[RUNE_FROST]) + dkPlayer->TakeRunes(RUNE_UNHOLY, runeCost[RUNE_UNHOLY]);
4468 if (missingRunes > 0 && dkPlayer->TakeRunes(RUNE_DEATH, missingRunes) > 0)
4469 return SPELL_FAILED_NO_POWER;
4470
4471 // Death knights gains some runic power when using runes
4472 if (spellRuneCost->runePowerGain > 0)
4473 {
4474 const auto runicPowerAmount = static_cast<uint32_t>((spellRuneCost->runePowerGain + dkPlayer->getPower(POWER_TYPE_RUNIC_POWER)) * worldConfig.getFloatRate(RATE_POWER7));
4475 dkPlayer->setPower(POWER_TYPE_RUNIC_POWER, runicPowerAmount);
4476 }
4477 }
4478 }
4479 }
4480 }
4481
4482 return SPELL_CAST_SUCCESS;
4483}
@ RUNE_UNHOLY
@ RUNE_DEATH
@ RUNE_FROST
@ RUNE_BLOOD
@ POWER_TYPE_RUNIC_POWER
Definition PowerType.hpp:24
SERVER_DECL WDB::WDBContainer< WDB::Structures::SpellRuneCostEntry > sSpellRuneCostStore
@ RATE_POWER7
Definition WorldConfig.h:21
Here is the call graph for this function:
Here is the caller graph for this function:

◆ checkShapeshift()

SpellCastResult Spell::checkShapeshift ( SpellInfo const spellInfo,
const uint32_t  shapeshiftForm 
) const
private

Definition at line 4486 of file Spell.cpp.

4487{
4488#if VERSION_STRING < Mop
4489 // No need to check requirements for talents that learn spells
4490 uint8_t talentRank = 0;
4491 const auto talentInfo = sTalentStore.lookupEntry(spellInfo->getId());
4492 if (talentInfo != nullptr)
4493 {
4494 for (uint8_t i = 0; i < 5; ++i)
4495 {
4496 if (talentInfo->RankID[i] != 0)
4497 talentRank = i + 1U;
4498 }
4499 }
4500
4501 // This is client-side only
4502 if (talentRank > 0 && spellInfo->hasEffect(SPELL_EFFECT_LEARN_SPELL))
4503 return SPELL_CAST_SUCCESS;
4504
4505 const uint32_t stanceMask = shapeshiftForm ? 1 << (shapeshiftForm - 1U) : 0U;
4506
4507 // Cannot explicitly be casted in this stance/form
4508 if (spellInfo->getShapeshiftExclude() > 0 && spellInfo->getShapeshiftExclude() & stanceMask)
4510
4511 // Can explicitly be casted in this stance/form
4512 if (spellInfo->getRequiredShapeShift() > 0 && spellInfo->getRequiredShapeShift() & stanceMask)
4513 return SPELL_CAST_SUCCESS;
4514
4515 auto actAsShifted = false;
4516 if (stanceMask > FORM_NORMAL)
4517 {
4518 auto shapeShift = sSpellShapeshiftFormStore.lookupEntry(shapeshiftForm);
4519 if (shapeShift == nullptr)
4520 {
4521 sLogger.failure("Spell::checkShapeshift: Caster has unknown shapeshift form {}", shapeshiftForm);
4522 return SPELL_CAST_SUCCESS;
4523 }
4524
4525 // Check if shapeshift acts as normal form for spells
4526 actAsShifted = !(shapeShift->Flags & 1);
4527 }
4528
4529 if (actAsShifted)
4530 {
4531 // Cannot be casted while shapeshifted
4532 if (spellInfo->getAttributes() & ATTRIBUTES_NOT_SHAPESHIFT)
4534 // Needs another shapeshift form
4535 else if (spellInfo->getRequiredShapeShift() != 0)
4537 }
4538 else
4539 {
4540 // Check if spell even requires shapeshift
4541 if (!(spellInfo->getAttributesExB() & ATTRIBUTESEXB_NOT_NEED_SHAPESHIFT) && spellInfo->getRequiredShapeShift() != 0)
4543 }
4544 return SPELL_CAST_SUCCESS;
4545#else
4547#endif
4548}
@ ATTRIBUTESEXB_NOT_NEED_SHAPESHIFT
@ SPELL_FAILED_ONLY_SHAPESHIFT
@ SPELL_FAILED_NOT_SHAPESHIFT
SERVER_DECL WDB::WDBContainer< WDB::Structures::TalentEntry > sTalentStore
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CreateItem()

void Spell::CreateItem ( uint32_t  itemId)

Creates number of items equal to a "damage" of the effect

Definition at line 2720 of file Spell.Legacy.cpp.

2721{
2722 /// Creates number of items equal to a "damage" of the effect
2723 if (itemId == 0 || p_caster == nullptr)
2724 return;
2725
2727}
bool AddItemById(uint32_t itemid, uint32_t count, int32_t randomprop)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DetermineSkillUp() [1/3]

void Spell::DetermineSkillUp ( )

Definition at line 1599 of file Spell.Legacy.cpp.

1600{
1601 if (p_caster == nullptr)
1602 return;
1603
1604 auto skill_line_ability = sSpellMgr.getFirstSkillEntryForSpell(getSpellInfo()->getId());
1605 if (skill_line_ability == nullptr)
1606 return;
1607
1608 float chance = 0.0f;
1609
1610 const auto skillLine = static_cast<uint16_t>(skill_line_ability->skilline);
1611 if (p_caster->hasSkillLine(skillLine))
1612 {
1613 uint32_t amt = p_caster->getSkillLineCurrent(skillLine, false);
1614 uint32_t max = p_caster->getSkillLineMax(skillLine);
1615 if (amt >= max)
1616 return;
1617 if (amt >= skill_line_ability->grey) //grey
1618 chance = 0.0f;
1619 else if ((amt >= (((skill_line_ability->grey - skill_line_ability->green) / 2) + skill_line_ability->green))) //green
1620 chance = 33.0f;
1621 else if (amt >= skill_line_ability->green) //yellow
1622 chance = 66.0f;
1623 else //brown
1624 chance = 100.0f;
1625 }
1626 if (Util::checkChance(chance * worldConfig.getFloatRate(RATE_SKILLCHANCE)))
1627 p_caster->advanceSkillLine(skillLine, static_cast<uint16_t>(Util::float2int32(1.0f * worldConfig.getFloatRate(RATE_SKILLRATE))));
1628}
@ RATE_SKILLCHANCE
Definition WorldConfig.h:37
@ RATE_SKILLRATE
Definition WorldConfig.h:38
bool hasSkillLine(uint16_t skillLine, bool strict=false) const
Definition Player.cpp:4912
void advanceSkillLine(uint16_t skillLine, uint16_t amount=1)
Definition Player.cpp:4713
uint16_t getSkillLineMax(uint16_t skillLine) const
Definition Player.cpp:4944
T max(const T &x, const T &y)
Definition g3dmath.h:320
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DetermineSkillUp() [2/3]

void Spell::DetermineSkillUp ( uint16_t  skillid)

Definition at line 2857 of file Spell.Legacy.cpp.

2858{
2859 //This code is wrong for creating items and disenchanting.
2860 if (p_caster == nullptr)
2861 return;
2862
2863 auto skill_line_ability = sSpellMgr.getFirstSkillEntryForSpell(getSpellInfo()->getId());
2864 if (skill_line_ability != nullptr && skillid == skill_line_ability->skilline && p_caster->hasSkillLine(skillid))
2865 {
2866 float chance = 0.0f;
2867 uint32_t amt = p_caster->getSkillLineCurrent(skillid, false);
2869 if (amt >= max)
2870 return;
2871 if (amt >= skill_line_ability->grey) //grey
2872 chance = 0.0f;
2873 else if ((amt >= (((skill_line_ability->grey - skill_line_ability->green) / 2) + skill_line_ability->green))) //green
2874 chance = 33.0f;
2875 else if (amt >= skill_line_ability->green) //yellow
2876 chance = 66.0f;
2877 else //brown
2878 chance = 100.0f;
2879
2880 if (Util::checkChance(chance * worldConfig.getFloatRate(RATE_SKILLCHANCE)))
2881 p_caster->advanceSkillLine(skillid, static_cast<uint16_t>(Util::float2int32(1.0f * worldConfig.getFloatRate(RATE_SKILLRATE))));
2882 }
2883}
Here is the call graph for this function:

◆ DetermineSkillUp() [3/3]

void Spell::DetermineSkillUp ( uint16_t  skillid,
uint32_t  targetlevel,
uint32_t  multiplicator = 1 
)

Definition at line 2731 of file Spell.Legacy.cpp.

2732{
2733 if (p_caster == nullptr)
2734 return;
2735
2736 if (p_caster->getSkillUpChance(skillid) < 0.01)
2737 return;//to prevent getting higher skill than max
2738
2739 int32_t diff = p_caster->getSkillLineCurrent(skillid, false) / 5 - targetlevel;
2740
2741 if (diff < 0)
2742 diff = -diff;
2743
2744 float chance;
2745 if (diff <= 5)
2746 chance = 95.0f;
2747 else if (diff <= 10)
2748 chance = 66.0f;
2749 else if (diff <= 15)
2750 chance = 33.0f;
2751 else
2752 return;
2753
2754 if (multiplicator == 0)
2755 multiplicator = 1;
2756
2757 if (Util::checkChance((chance * worldConfig.getFloatRate(RATE_SKILLCHANCE)) * multiplicator))
2758 {
2759 p_caster->advanceSkillLine(skillid, static_cast<uint16_t>(Util::float2int32(1.0f * worldConfig.getFloatRate(RATE_SKILLRATE))));
2760
2761 uint32_t value = p_caster->getSkillLineCurrent(skillid, true);
2762 uint32_t spellid = 0;
2763
2764 // Lifeblood
2765 if (skillid == SKILL_HERBALISM)
2766 {
2767 switch (value)
2768 {
2769 case 75:
2770 { spellid = 55428; }
2771 break;// Rank 1
2772 case 150:
2773 { spellid = 55480; }
2774 break;// Rank 2
2775 case 225:
2776 { spellid = 55500; }
2777 break;// Rank 3
2778 case 300:
2779 { spellid = 55501; }
2780 break;// Rank 4
2781 case 375:
2782 { spellid = 55502; }
2783 break;// Rank 5
2784 case 450:
2785 { spellid = 55503; }
2786 break;// Rank 6
2787 case 525:
2788 { spellid = 74497; }
2789 break;// Rank 7
2790 }
2791 }
2792
2793 // Toughness
2794 else if (skillid == SKILL_MINING)
2795 {
2796 switch (value)
2797 {
2798 case 75:
2799 { spellid = 53120; }
2800 break;// Rank 1
2801 case 150:
2802 { spellid = 53121; }
2803 break;// Rank 2
2804 case 225:
2805 { spellid = 53122; }
2806 break;// Rank 3
2807 case 300:
2808 { spellid = 53123; }
2809 break;// Rank 4
2810 case 375:
2811 { spellid = 53124; }
2812 break;// Rank 5
2813 case 450:
2814 { spellid = 53040; }
2815 break;// Rank 6
2816 case 525:
2817 { spellid = 74496; }
2818 break;// Rank 7
2819 }
2820 }
2821
2822
2823 // Master of Anatomy
2824 else if (skillid == SKILL_SKINNING)
2825 {
2826 switch (value)
2827 {
2828 case 75:
2829 { spellid = 53125; }
2830 break;// Rank 1
2831 case 150:
2832 { spellid = 53662; }
2833 break;// Rank 2
2834 case 225:
2835 { spellid = 53663; }
2836 break;// Rank 3
2837 case 300:
2838 { spellid = 53664; }
2839 break;// Rank 4
2840 case 375:
2841 { spellid = 53665; }
2842 break;// Rank 5
2843 case 450:
2844 { spellid = 53666; }
2845 break;// Rank 6
2846 case 525:
2847 { spellid = 74495; }
2848 break;// Rank 7
2849 }
2850 }
2851
2852 if (spellid != 0)
2853 p_caster->addSpell(spellid, skillid);
2854 }
2855}
@ SKILL_SKINNING
Definition Skill.hpp:134
float getSkillUpChance(uint16_t id)
Definition Player.cpp:5191
void addSpell(uint32_t spellId, uint16_t fromSkill=0)
Definition Player.cpp:3935
Here is the call graph for this function:

◆ DidHit()

uint8_t Spell::DidHit ( uint32_t  effindex,
Unit target 
)
Todo:
SB@L - This mechanic resist chance is handled twice, once several lines above, then as part of resistchance here check mechanical resistance i have no idea what is the best pace for this code

Definition at line 417 of file Spell.Legacy.cpp.

418{
419 //note resistchance is vise versa, is full hit chance
420 Unit* u_victim = target;
421 if (u_victim == nullptr)
422 return SPELL_DID_HIT_MISS;
423
424 Player* p_victim = target->isPlayer() ? static_cast<Player*>(target) : NULL;
425
426 float baseresist[3] = { 4.0f, 5.0f, 6.0f };
427 int32_t lvldiff;
428 float resistchance;
429
430
431 /************************************************************************/
432 /* Can't resist non-unit */
433 /************************************************************************/
434 if (u_caster == nullptr)
436
437 /************************************************************************/
438 /* Can't reduce your own spells */
439 /************************************************************************/
440 if (u_caster == u_victim)
442
443 /************************************************************************/
444 /* Check if the player target is able to deflect spells */
445 /* Currently (3.3.5a) there is only spell doing that: Deterrence */
446 /************************************************************************/
447#if VERSION_STRING >= WotLK
448 if (p_victim && p_victim->hasAuraWithAuraEffect(SPELL_AURA_DEFLECT_SPELLS))
449 {
451 }
452#endif
453
454 // APGL End
455 // MIT Start
456
457 // Check if creature target is in evade mode
458 if (target->isCreature() && target->isInEvadeMode())
459 return SPELL_DID_HIT_EVADE;
460
461 // Check if unit target is immune to this spell effect
462 if (target->getSpellImmunity() != SPELL_IMMUNITY_NONE)
463 {
465 {
466 if (getSpellInfo()->getMechanicsType() == MECHANIC_CHARMED ||
467 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_CHARMED)
469 }
470
472 {
473 if (getSpellInfo()->getMechanicsType() == MECHANIC_DISORIENTED ||
474 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_DISORIENTED)
476 }
477
479 {
480 if (getSpellInfo()->getMechanicsType() == MECHANIC_FLEEING ||
481 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_FLEEING)
483
484 if (getSpellInfo()->getMechanicsType() == MECHANIC_HORRIFIED ||
485 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_HORRIFIED)
487
488 if (getSpellInfo()->getMechanicsType() == MECHANIC_TURNED ||
489 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_TURNED)
491 }
492
494 {
495 if (getSpellInfo()->getMechanicsType() == MECHANIC_ROOTED ||
496 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_ROOTED)
498 }
499
501 {
502 if (getSpellInfo()->getMechanicsType() == MECHANIC_SILENCED ||
503 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_SILENCED)
505 }
506
508 {
509 if (getSpellInfo()->getMechanicsType() == MECHANIC_STUNNED ||
510 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_STUNNED)
512 }
513
515 {
516 if (getSpellInfo()->getMechanicsType() == MECHANIC_POLYMORPHED ||
517 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_POLYMORPHED)
519 }
520
522 {
523 if (getSpellInfo()->getMechanicsType() == MECHANIC_BANISHED ||
524 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_BANISHED)
526 }
527
529 {
530 if (getSpellInfo()->getMechanicsType() == MECHANIC_SAPPED ||
531 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_SAPPED)
533 }
534
536 {
537 if (getSpellInfo()->getMechanicsType() == MECHANIC_FROZEN ||
538 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_FROZEN)
540 }
541
543 {
544 if (getSpellInfo()->getMechanicsType() == MECHANIC_ENSNARED ||
545 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_ENSNARED)
547 }
548
550 {
551 if (getSpellInfo()->getMechanicsType() == MECHANIC_ASLEEP ||
552 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_ASLEEP)
554 }
555
557 {
558 if (getSpellInfo()->getEffect(effindex) == SPELL_EFFECT_ATTACK_ME ||
559 getSpellInfo()->getEffectApplyAuraName(effindex) == SPELL_AURA_MOD_TAUNT)
561 }
562
563#if VERSION_STRING >= TBC
565 {
566 if (getSpellInfo()->getEffectApplyAuraName(effindex) == SPELL_AURA_INCREASE_CASTING_TIME_PCT)
568 }
569#endif
570
572 {
573 if (getSpellInfo()->getMechanicsType() == MECHANIC_INTERRUPTED ||
574 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_INTERRUPTED)
576 }
577
579 {
580 if (getSpellInfo()->getEffectApplyAuraName(effindex) == SPELL_AURA_MOD_HEALING_DONE_PERCENT)
581 {
582 // Prevent only effects with negative value
583 const auto val = getSpellInfo()->calculateEffectValue(effindex);
584 if (val < 0)
586 }
587 }
588
590 {
591 if (getSpellInfo()->getEffectApplyAuraName(effindex) == SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE)
592 {
593 // Prevent only effects with negative value
594 const auto val = getSpellInfo()->calculateEffectValue(effindex);
595 if (val < 0)
597 }
598 }
599
601 {
602 if (getSpellInfo()->getEffect(effindex) == SPELL_EFFECT_KNOCK_BACK
603#if VERSION_STRING >= TBC
604 || getSpellInfo()->getEffect(effindex) == SPELL_EFFECT_KNOCK_BACK_DEST
605#endif
606 )
608 }
609
611 {
612 if (getSpellInfo()->getMechanicsType() == MECHANIC_DISARMED ||
613 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_DISARMED)
615 }
616
618 {
619 if (getSpellInfo()->getMechanicsType() == MECHANIC_INCAPACIPATED ||
620 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_INCAPACIPATED)
622 }
623
625 {
626 if (getSpellInfo()->getMechanicsType() == MECHANIC_BLEEDING ||
627 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_BLEEDING)
629 }
630
632 {
633 if (getSpellInfo()->getMechanicsType() == MECHANIC_SHACKLED ||
634 getSpellInfo()->getEffectMechanic(effindex) == MECHANIC_SHACKLED)
636 }
637 }
638
639 // Check if target can reflect this spell
641 {
642 auto isReflected = false;
643 for (const auto& reflectAura : u_victim->m_reflectSpellSchool)
644 {
645 if (reflectAura->school != -1 && reflectAura->school != getSpellInfo()->getFirstSchoolFromSchoolMask())
646 continue;
647
648 if (Util::checkChance(static_cast<float_t>(reflectAura->chance)))
649 {
650 //the god blessed special case : mage - Frost Warding = is an augmentation to frost warding
651 if (reflectAura->spellId != 0 && !u_victim->hasAurasWithId(reflectAura->spellId))
652 continue;
653
654 if (reflectAura->infront)
655 {
656 if (m_caster->isInFront(u_victim))
657 isReflected = true;
658 }
659 else
660 {
661 isReflected = true;
662 }
663
664 if (reflectAura->charges > 0)
665 {
666 reflectAura->charges--;
667 if (reflectAura->charges <= 0)
668 {
669 // should delete + erase RSS too, if unit hasn't such an aura...
670 if (!u_victim->hasAurasWithId(reflectAura->spellId))
671 {
672 // ...do it manually
673 u_victim->m_reflectSpellSchool.remove(reflectAura);
674 }
675 else
676 {
677 u_victim->removeAllAurasById(reflectAura->spellId);
678 }
679 }
680 }
681
682 break;
683 }
684 }
685
686 if (isReflected)
688 }
689
690 // MIT End
691 // APGL Start
692
693 /************************************************************************/
694 /* Check if the target is immune to this spell school */
695 /* Unless the spell would actually dispel invulnerabilities */
696 /************************************************************************/
698 if (u_victim->m_schoolImmunityList[getSpellInfo()->getFirstSchoolFromSchoolMask()] && !dispelMechanic)
700
701 /* Check if player target has god mode */
702 if (p_victim && p_victim->m_cheats.hasGodModeCheat)
703 {
705 }
706
707 /*************************************************************************/
708 /* Check if the target is immune to this mechanic */
709 /*************************************************************************/
710 if (getSpellInfo()->getMechanicsType() < TOTAL_SPELL_MECHANICS && u_victim->m_mechanicsDispels[getSpellInfo()->getMechanicsType()])
711
712 {
713 // Immune - IF, and ONLY IF, there is no damage component!
714 bool no_damage_component = true;
715 for (uint8_t x = 0; x <= 2; x++)
716 {
717 if (getSpellInfo()->getEffect(x) == SPELL_EFFECT_SCHOOL_DAMAGE
719 || getSpellInfo()->getEffect(x) == SPELL_EFFECT_WEAPON_DAMAGE
721 || getSpellInfo()->getEffect(x) == SPELL_EFFECT_DUMMY
722 || (getSpellInfo()->getEffect(x) == SPELL_EFFECT_APPLY_AURA &&
723 (getSpellInfo()->getEffectApplyAuraName(x) == SPELL_AURA_PERIODIC_DAMAGE
724 ))
725 )
726 {
727 no_damage_component = false;
728 break;
729 }
730 }
731 if (no_damage_component)
732 return SPELL_DID_HIT_IMMUNE; // Moved here from Spell::CanCast
733 }
734
735 /************************************************************************/
736 /* Check if the target has a % resistance to this mechanic */
737 /************************************************************************/
738 if (getSpellInfo()->getMechanicsType() < TOTAL_SPELL_MECHANICS)
739 {
740 float res = u_victim->m_mechanicsResistancesPct[getSpellInfo()->getMechanicsType()];
741 if (Util::checkChance(res))
743 }
744
745 /************************************************************************/
746 /* Check if the spell is a melee attack and if it was missed/parried */
747 /************************************************************************/
748 uint32_t melee_test_result;
749 if (getSpellInfo()->getDmgClass() == SPELL_DMG_TYPE_MELEE || getSpellInfo()->getDmgClass() == SPELL_DMG_TYPE_RANGED)
750 {
751 uint32_t _type;
753 _type = RANGED;
754 else
755 {
757 _type = OFFHAND;
758 else
759 _type = MELEE;
760 }
761
762 melee_test_result = u_caster->getSpellDidHitResult(u_victim, _type, this);
763 if (melee_test_result != SPELL_DID_HIT_SUCCESS)
764 return (uint8_t)melee_test_result;
765 }
766
767 /************************************************************************/
768 /* Check if the spell is resisted. */
769 /************************************************************************/
770 if (getSpellInfo()->getFirstSchoolFromSchoolMask() == SCHOOL_NORMAL && getSpellInfo()->getMechanicsType() == MECHANIC_NONE)
772
773 bool pvp = (p_caster && p_victim);
774
775 if (pvp)
776 lvldiff = p_victim->getLevel() - p_caster->getLevel();
777 else
778 lvldiff = u_victim->getLevel() - u_caster->getLevel();
779 if (lvldiff < 0)
780 {
781 resistchance = baseresist[0] + lvldiff;
782 }
783 else
784 {
785 if (lvldiff < 3)
786 {
787 resistchance = baseresist[lvldiff];
788 }
789 else
790 {
791 if (pvp)
792 resistchance = baseresist[2] + (((float)lvldiff - 2.0f) * 7.0f);
793 else
794 resistchance = baseresist[2] + (((float)lvldiff - 2.0f) * 11.0f);
795 }
796 }
797 ///\todo SB@L - This mechanic resist chance is handled twice, once several lines above, then as part of resistchance here check mechanical resistance i have no idea what is the best pace for this code
799 {
800 resistchance += u_victim->m_mechanicsResistancesPct[getSpellInfo()->getMechanicsType()];
801 }
802 //rating bonus
803 if (p_caster != nullptr)
804 {
805 resistchance -= p_caster->calcRating(CR_HIT_SPELL);
806 resistchance -= p_caster->getHitFromSpell();
807 }
808
809 // school hit resistance: check all schools and take the minimal
810 if (p_victim != nullptr && getSpellInfo()->getSchoolMask() > 0)
811 {
812 int32_t min = 100;
813 for (uint8_t i = 0; i < TOTAL_SPELL_SCHOOLS; i++)
814 {
815 if (getSpellInfo()->getSchoolMask() & (1 << i) && min > p_victim->m_resistHitSpell[i])
816 min = p_victim->m_resistHitSpell[i];
817 }
818 resistchance += min;
819 }
820
821 if (getSpellInfo()->getEffect(static_cast<uint8_t>(effindex)) == SPELL_EFFECT_DISPEL)
822 {
824 }
825
826 float hitchance = 0;
828 resistchance -= hitchance;
829
831 resistchance = 0.0f;
832
833 if (resistchance >= 100.0f)
835 else
836 {
837 uint8_t res;
838 if (resistchance <= 1.0) //resist chance >=1
840 else
842
843 if (res == SPELL_DID_HIT_SUCCESS) // proc handling. mb should be moved outside this function
844 {
845 // u_caster->HandleProc(PROC_ON_SPELL_LAND,target,GetProto());
846 }
847
848 return res;
849 }
850}
@ SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE
@ SPELL_AURA_PERIODIC_DAMAGE
@ SPELL_AURA_MOD_HEALING_DONE_PERCENT
@ SPELL_AURA_DEFLECT_SPELLS
@ SPELL_AURA_MOD_TAUNT
@ SPELL_AURA_INCREASE_CASTING_TIME_PCT
@ CR_HIT_SPELL
@ TOTAL_SPELL_SCHOOLS
Definition School.hpp:19
@ SCHOOL_NORMAL
Definition School.hpp:12
@ SPELL_DID_HIT_EVADE
@ SPELL_DID_HIT_IMMUNE
@ SPELL_DID_HIT_DEFLECT
@ SPELL_DID_HIT_RESIST
@ SPELL_EFFECT_DISPEL_MECHANIC
@ SPELL_EFFECT_DISPEL
@ SPELL_EFFECT_ATTACK_ME
@ SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
@ SPELL_EFFECT_KNOCK_BACK_DEST
@ SPELL_EFFECT_KNOCK_BACK
@ SPELL_EFFECT_APPLY_AURA
@ MECHANIC_BLEEDING
@ MECHANIC_ROOTED
@ MECHANIC_NONE
@ MECHANIC_ENSNARED
@ MECHANIC_SHACKLED
@ MECHANIC_INVULNERABLE
@ MECHANIC_DISORIENTED
@ MECHANIC_FLEEING
@ MECHANIC_POLYMORPHED
@ MECHANIC_DISARMED
@ MECHANIC_ASLEEP
@ TOTAL_SPELL_MECHANICS
@ MECHANIC_INCAPACIPATED
@ MECHANIC_CHARMED
@ MECHANIC_TURNED
@ MECHANIC_INTERRUPTED
@ MECHANIC_SILENCED
@ MECHANIC_SAPPED
@ MECHANIC_BANISHED
@ MECHANIC_HORRIFIED
@ SPELLMOD_HITCHANCE
@ SPELLMOD_RESIST_DISPEL
@ SPELL_IMMUNITY_INTERRUPT_CAST
@ SPELL_IMMUNITY_CONFUSE
@ SPELL_IMMUNITY_POLYMORPH
@ SPELL_IMMUNITY_TOTAL_STATS
@ SPELL_IMMUNITY_STUN
@ SPELL_IMMUNITY_INCAPACITATE
@ SPELL_IMMUNITY_BLEED
@ SPELL_IMMUNITY_SILENCE
@ SPELL_IMMUNITY_FEAR
@ SPELL_IMMUNITY_SHACKLE
@ SPELL_IMMUNITY_SAP
@ SPELL_IMMUNITY_DISARM
@ SPELL_IMMUNITY_CHARM
@ SPELL_IMMUNITY_TAUNT
@ SPELL_IMMUNITY_BANISH
@ SPELL_IMMUNITY_ROOT
@ SPELL_IMMUNITY_FROZEN
@ SPELL_IMMUNITY_SLEEP
@ SPELL_IMMUNITY_SPELL_HASTE
@ SPELL_IMMUNITY_SLOW
@ SPELL_IMMUNITY_MOD_HEALING
@ SPELL_IMMUNITY_KNOCKBACK
@ SPELL_IMMUNITY_NONE
float getHitFromSpell()
Definition Player.hpp:2036
float calcRating(PlayerCombatRating t)
Definition Player.cpp:16170
int32_t m_resistHitSpell[TOTAL_SPELL_SCHOOLS]
Definition Player.hpp:2058
bool hasAttributeExC(SpellAttributesExC _attribute) const
Definition Spell.cpp:5809
uint32_t GetType()
float m_mechanicsResistancesPct[32]
Definition Unit.hpp:1419
uint32_t getSpellImmunity() const
Definition Unit.cpp:4525
uint32_t getSpellDidHitResult(Unit *pVictim, uint32_t weapon_damage_type, Spell *castingSpell)
Combat.
Definition Unit.cpp:10178
bool isInEvadeMode() const
Definition Unit.hpp:722
std::list< std::unique_ptr< ReflectSpellSchool > > m_reflectSpellSchool
Definition Unit.hpp:1280
uint32_t m_mechanicsDispels[32]
Definition Unit.hpp:1416
uint32_t m_schoolImmunityList[TOTAL_SPELL_SCHOOLS]
Definition Unit.hpp:1451
bool hasSpellImmunity(SpellImmunityMask immunityMask) const
Definition Unit.cpp:4530
T min(const T &x, const T &y)
Definition g3dmath.h:305
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DoAfterHandleEffect()

void Spell::DoAfterHandleEffect ( Unit target,
uint32_t  i 
)
protectedvirtual

Reimplemented in RuneStrileSpell, BloodStrikeSpell, HeartStrikeSpell, DispersionSpell, FirestarterTalent, and MissileBarrage.

Definition at line 2670 of file Spell.Legacy.cpp.

2671{
2672}
Here is the caller graph for this function:

◆ DoCalculateEffect()

int32_t Spell::DoCalculateEffect ( uint32_t  i,
Unit target,
int32_t  value 
)
protectedvirtual

Reimplemented in BloodPlagueSpell, IcyTouchSpell, FrostFeverSpell, VampiricBloodSpell, InnervateSpell, BloodBoilSpell, BloodwormSpell, and BloodStrikeSpell.

Definition at line 2021 of file Spell.Legacy.cpp.

2022{
2023 //1 switch: checking spell id. If the spell is not handled in the first block,
2024 //2nd block of checks is reached. bool handled is initialized as true and set to false in the default: case of each switch.
2025 bool handled = true;
2026
2027 switch (getSpellInfo()->getId())
2028 {
2029 // SPELL_HASH_STEADY_SHOT:
2030 case 34120:
2031 case 49051:
2032 case 49052:
2033 case 56641:
2034 case 65867:
2035 {
2036 if (u_caster != nullptr && i == 0)
2037 {
2038 if (p_caster != nullptr)
2039 {
2040 Item* it;
2042 if (it)
2043 {
2044 float weapondmg = Util::getRandomFloat(1) * (it->getItemProperties()->Damage[0].Max - it->getItemProperties()->Damage[0].Min) + it->getItemProperties()->Damage[0].Min;
2045 value += Util::float2int32(getSpellInfo()->getEffectBasePoints(0) + weapondmg / (it->getItemProperties()->Delay / 1000.0f) * 2.8f);
2046 }
2047 }
2048 if (target && target->isDazed())
2051 }
2052 } break;
2053
2054 // SPELL_HASH_REND:
2055 case 772:
2056 case 6546:
2057 case 6547:
2058 case 6548:
2059 case 11572:
2060 case 11573:
2061 case 11574:
2062 case 11977:
2063 case 12054:
2064 case 13318:
2065 case 13443:
2066 case 13445:
2067 case 13738:
2068 case 14087:
2069 case 14118:
2070 case 16393:
2071 case 16403:
2072 case 16406:
2073 case 16509:
2074 case 17153:
2075 case 17504:
2076 case 18075:
2077 case 18078:
2078 case 18106:
2079 case 18200:
2080 case 18202:
2081 case 21949:
2082 case 25208:
2083 case 29574:
2084 case 29578:
2085 case 36965:
2086 case 36991:
2087 case 37662:
2088 case 43246:
2089 case 43931:
2090 case 46845:
2091 case 47465:
2092 case 48880:
2093 case 53317:
2094 case 54703:
2095 case 54708:
2096 case 59239:
2097 case 59343:
2098 case 59691:
2099 {
2100 if (p_caster != nullptr)
2101 {
2102 Item* it;
2104 if (it)
2105 {
2106 if (it->getItemProperties()->Class == 2)
2107 {
2108 float avgwepdmg = (it->getItemProperties()->Damage[0].Min + it->getItemProperties()->Damage[0].Max) * 0.5f;
2109 float wepspd = (it->getItemProperties()->Delay * 0.001f);
2110 int32_t dmg = Util::float2int32((avgwepdmg)+p_caster->getCalculatedAttackPower() / 14 * wepspd);
2111
2112 if (target && target->getHealthPct() > 75)
2113 {
2114 dmg = Util::float2int32(dmg + dmg * 0.35f);
2115 }
2116
2117 value += dmg / 5;
2118 }
2119 }
2120 }
2121 } break;
2122
2123 // SPELL_HASH_SLAM:
2124 case 1464:
2125 case 8820:
2126 case 11430:
2127 case 11604:
2128 case 11605:
2129 case 25241:
2130 case 25242:
2131 case 34620:
2132 case 47474:
2133 case 47475:
2134 case 50782:
2135 case 50783:
2136 case 52026:
2137 case 67028:
2138 {
2139 if (p_caster != nullptr)
2140 {
2142 if (mainHand != nullptr)
2143 {
2144 float avgWeaponDmg = (mainHand->getItemProperties()->Damage[0].Max + mainHand->getItemProperties()->Damage[0].Min) / 2;
2145 value += Util::float2int32((getSpellInfo()->calculateEffectValue(0)) + avgWeaponDmg);
2146 }
2147 }
2148 } break;
2149
2150 // SPELL_HASH_EVISCERATE:
2151 case 2098:
2152 case 6760:
2153 case 6761:
2154 case 6762:
2155 case 8623:
2156 case 8624:
2157 case 11299:
2158 case 11300:
2159 case 15691:
2160 case 15692:
2161 case 26865:
2162 case 27611:
2163 case 31016:
2164 case 41177:
2165 case 46189:
2166 case 48667:
2167 case 48668:
2168 case 57641:
2169 case 60008:
2170 case 65957:
2171 case 67709:
2172 case 68094:
2173 case 68095:
2174 case 68096:
2175 case 68317:
2176 case 71933:
2177 {
2178 if (p_caster != nullptr)
2180 } break;
2181
2182 // SPELL_HASH_FEROCIOUS_BITE:
2183 case 22568:
2184 case 22827:
2185 case 22828:
2186 case 22829:
2187 case 24248:
2188 case 27557:
2189 case 31018:
2190 case 48576:
2191 case 48577:
2192 {
2193 if (p_caster != nullptr)
2194 {
2197 }
2198 } break;
2199
2200 // SPELL_HASH_VICTORY_RUSH:
2201 case 34428:
2202 {
2203 //causing ${$AP*$m1/100} damage
2204 if (u_caster != nullptr && i == 0)
2206 } break;
2207
2208 // SPELL_HASH_RAKE:
2209 case 1822:
2210 case 1823:
2211 case 1824:
2212 case 9904:
2213 case 24331:
2214 case 24332:
2215 case 27003:
2216 case 27556:
2217 case 27638:
2218 case 36332:
2219 case 48573:
2220 case 48574:
2221 case 53499:
2222 case 54668:
2223 case 59881:
2224 case 59882:
2225 case 59883:
2226 case 59884:
2227 case 59885:
2228 case 59886:
2229 {
2230 //Rake the target for ${$AP/100+$m1} bleed damage and an additional ${$m2*3+$AP*0.06} damage over $d.
2231 if (u_caster != nullptr)
2232 {
2233 float ap = float(u_caster->getCalculatedAttackPower());
2234 if (i == 0)
2235 value += Util::float2int32(ceilf(ap * 0.01f)); // / 100
2236 else if (i == 1)
2237 value += Util::float2int32(ap * 0.06f);
2238 }
2239 } break;
2240
2241 // SPELL_HASH_GARROTE:
2242 case 703:
2243 case 8631:
2244 case 8632:
2245 case 8633:
2246 case 8818:
2247 case 11289:
2248 case 11290:
2249 case 26839:
2250 case 26884:
2251 case 37066:
2252 case 48675:
2253 case 48676:
2254 {
2255 // WoWWiki says +(0.18 * attack power / number of ticks)
2256 // Tooltip gives no specific reading, but says ", increased by your attack power.".
2257 if (u_caster != nullptr && i == 0)
2258 value += (uint32_t)ceilf((u_caster->getCalculatedAttackPower() * 0.07f) / 6);
2259 } break;
2260
2261 // SPELL_HASH_RUPTURE:
2262 case 1943:
2263 case 8639:
2264 case 8640:
2265 case 11273:
2266 case 11274:
2267 case 11275:
2268 case 14874:
2269 case 14903:
2270 case 15583:
2271 case 26867:
2272 case 48671:
2273 case 48672:
2274 {
2275 /*
2276 1pt = Attack Power * 0.04 + x
2277 2pt = Attack Power * 0.10 + y
2278 3pt = Attack Power * 0.18 + z
2279 4pt = Attack Power * 0.21 + a
2280 5pt = Attack Power * 0.24 + b
2281 */
2282 if (p_caster != nullptr && i == 0)
2283 {
2285 value += (uint32_t)ceilf((u_caster->getCalculatedAttackPower() * 0.04f * cp) / ((6 + (cp << 1)) >> 1));
2286 }
2287 } break;
2288
2289 // SPELL_HASH_RIP:
2290 case 1079:
2291 case 9492:
2292 case 9493:
2293 case 9752:
2294 case 9894:
2295 case 9896:
2296 case 27008:
2297 case 33912:
2298 case 36590:
2299 case 49799:
2300 case 49800:
2301 case 57661:
2302 case 59989:
2303 case 71926:
2304 {
2305 if (p_caster != nullptr)
2307 } break;
2308
2309 // SPELL_HASH_MONGOOSE_BITE:
2310 case 1495:
2311 case 14269:
2312 case 14270:
2313 case 14271:
2314 case 36916:
2315 case 53339:
2316 {
2317 // ${$AP*0.2+$m1} damage.
2318 if (u_caster != nullptr)
2320 } break;
2321
2322 // SPELL_HASH_SWIPE:
2323 case 27554:
2324 case 31279:
2325 case 50256:
2326 case 53498:
2327 case 53526:
2328 case 53528:
2329 case 53529:
2330 case 53532:
2331 case 53533:
2332 {
2333 // ${$AP*0.06+$m1} damage.
2334 if (u_caster != nullptr)
2336 } break;
2337
2338 // SPELL_HASH_HAMMER_OF_THE_RIGHTEOUS:
2339 case 53595:
2340 case 54423:
2341 case 66867:
2342 case 66903:
2343 case 66904:
2344 case 66905:
2345 case 67680:
2346 {
2347 if (p_caster != nullptr)
2348 //4x 1h weapon-dps -> 4*(mindmg+maxdmg)/speed/2 = 2*(mindmg+maxdmg)/speed
2350 } break;
2351
2352 // SPELL_HASH_BACKSTAB: // Egari: spell 31220 is interfering with combopoints
2353 case 53:
2354 case 2589:
2355 case 2590:
2356 case 2591:
2357 case 7159:
2358 case 8721:
2359 case 11279:
2360 case 11280:
2361 case 11281:
2362 case 15582:
2363 case 15657:
2364 case 22416:
2365 case 25300:
2366 case 26863:
2367 case 30992:
2368 case 34614:
2369 case 37685:
2370 case 48656:
2371 case 48657:
2372 case 52540:
2373 case 58471:
2374 case 63754:
2375 case 71410:
2376 case 72427:
2377 {
2378 if (i == 2)
2379 return getSpellInfo()->getEffectBasePoints(static_cast<uint8_t>(i)) + 1;
2380 } break;
2381
2382 // SPELL_HASH_FAN_OF_KNIVES: // rogue - fan of knives
2383 case 51723:
2384 case 52874:
2385 case 61739:
2386 case 61740:
2387 case 61741:
2388 case 61742:
2389 case 61743:
2390 case 61744:
2391 case 61745:
2392 case 61746:
2393 case 63753:
2394 case 65955:
2395 case 67706:
2396 case 68097:
2397 case 68098:
2398 case 68099:
2399 case 69921:
2400 case 71128:
2401 {
2402 if (p_caster != nullptr)
2403 {
2405 if (mit != nullptr)
2406 {
2407 if (mit->getItemProperties()->Class == 2 && mit->getItemProperties()->SubClass == 15) // daggers
2408 value = 105;
2409 }
2410 }
2411 } break;
2412
2413 // SPELL_HASH_SEAL_OF_RIGHTEOUSNESS:
2414 case 20154:
2415 case 21084:
2416 case 25742:
2417 {
2418 if (p_caster != nullptr)
2419 {
2421 if (mit != nullptr)
2423 }
2424 } break;
2425
2426 // SPELL_HASH_BLOOD_CORRUPTION:
2427 case 53742:
2428 // SPELL_HASH_HOLY_VENGEANCE:
2429 case 31803:
2430 {
2431 if (p_caster != nullptr)
2433 } break;
2434
2435 // SPELL_HASH_JUDGEMENT:
2436 case 10321:
2437 case 23590:
2438 case 23591:
2439 case 35170:
2440 case 41467:
2441 case 43838:
2442 case 54158:
2443 {
2444 if (p_caster != nullptr)
2446 } break;
2447
2448 // SPELL_HASH_JUDGEMENT_OF_RIGHTEOUSNESS:
2449 case 20187:
2450 {
2451 if (p_caster != nullptr)
2453 } break;
2454
2455 // SPELL_HASH_JUDGEMENT_OF_VENGEANCE:
2456 case 31804:
2457 // SPELL_HASH_JUDGEMENT_OF_CORRUPTION:
2458 case 53733:
2459 {
2460 if (p_caster != nullptr)
2462 } break;
2463
2464 // SPELL_HASH_ENVENOM:
2465 case 32645:
2466 case 32684:
2467 case 39967:
2468 case 41487:
2469 case 41509:
2470 case 41510:
2471 case 57992:
2472 case 57993:
2473 {
2474 if (p_caster != nullptr && i == 0)
2475 {
2478 }
2479 } break;
2480
2481 //SPELL_HASH_GOUGE
2482 case 1776:
2483 case 1777:
2484 case 8629:
2485 case 11285:
2486 case 11286:
2487 case 12540:
2488 case 13579:
2489 case 24698:
2490 case 28456:
2491 case 29425:
2492 case 34940:
2493 case 36862:
2494 case 38764:
2495 case 38863:
2496 {
2497 if (u_caster != nullptr && i == 0)
2498 value += (uint32_t)ceilf(u_caster->getCalculatedAttackPower() * 0.21f);
2499 } break;
2500 default:
2501 {
2502 handled = false;
2503 } break;
2504 }
2505
2506 if (!handled)
2507 {
2508 //it will be set to false in the default case of the switch.
2509 handled = true;
2510 switch (getSpellInfo()->getId())
2511 {
2512 case 34123: //Druid - Tree of Life
2513 {
2514 if (p_caster != nullptr && i == 0)
2515 //Heal is increased by 6%
2516 value = Util::float2int32(value * 1.06f);
2517 break;
2518 }
2519 case 57669: //Replenishment
2520 case 61782:
2521 {
2522 if (p_caster != nullptr && i == 0 && target != nullptr)
2523 value = int32_t(0.002 * target->getMaxPower(POWER_TYPE_MANA));
2524 break;
2525 }
2526 default:
2527 {
2528 //not handled in this switch
2529 handled = false;
2530 break;
2531 }
2532 }
2533
2534 if (!handled)
2535 {
2536 if (getSpellInfo()->custom_c_is_flags & SPELL_FLAG_IS_POISON && u_caster != nullptr) // poison damage modifier
2537 {
2538 switch (getSpellInfo()->getId())
2539 {
2540 // SPELL_HASH_DEADLY_POISON_IX:
2541 case 57970:
2542 case 57973:
2543 // SPELL_HASH_DEADLY_POISON_VIII:
2544 case 57969:
2545 case 57972:
2546 // SPELL_HASH_DEADLY_POISON_VII:
2547 case 27186:
2548 case 27187:
2549 // SPELL_HASH_DEADLY_POISON_VI:
2550 case 26967:
2551 case 26968:
2552 // SPELL_HASH_DEADLY_POISON_V:
2553 case 25349:
2554 case 25351:
2555 // SPELL_HASH_DEADLY_POISON_IV:
2556 case 11354:
2557 case 11356:
2558 // SPELL_HASH_DEADLY_POISON_III:
2559 case 11353:
2560 case 11355:
2561 // SPELL_HASH_DEADLY_POISON_II:
2562 case 2819:
2563 case 2824:
2564 // SPELL_HASH_DEADLY_POISON:
2565 case 2818:
2566 case 2823:
2567 case 3583:
2568 case 10022:
2569 case 13582:
2570 case 21787:
2571 case 21788:
2572 case 32970:
2573 case 32971:
2574 case 34616:
2575 case 34655:
2576 case 34657:
2577 case 36872:
2578 case 38519:
2579 case 38520:
2580 case 41191:
2581 case 41192:
2582 case 41485:
2583 case 43580:
2584 case 43581:
2585 case 56145:
2586 case 56149:
2587 case 59479:
2588 case 59482:
2589 case 63755:
2590 case 63756:
2591 case 67710:
2592 case 67711:
2593 case 68315:
2594 case 72329:
2595 case 72330:
2596 if (getSpellInfo()->getEffectApplyAuraName(static_cast<uint8_t>(i)) == SPELL_AURA_PERIODIC_DAMAGE)
2598 break;
2599 // SPELL_HASH_INSTANT_POISON_IX:
2600 case 57965:
2601 case 57968:
2602 // SPELL_HASH_INSTANT_POISON_VIII:
2603 case 57964:
2604 case 57967:
2605 // SPELL_HASH_INSTANT_POISON_VII:
2606 case 26890:
2607 case 26891:
2608 // SPELL_HASH_INSTANT_POISON_VI:
2609 case 11337:
2610 case 11340:
2611 // SPELL_HASH_INSTANT_POISON_V:
2612 case 11336:
2613 case 11339:
2614 // SPELL_HASH_INSTANT_POISON_IV:
2615 case 11335:
2616 case 11338:
2617 // SPELL_HASH_INSTANT_POISON_III:
2618 case 8688:
2619 case 8689:
2620 // SPELL_HASH_INSTANT_POISON_II:
2621 case 8685:
2622 case 8686:
2623 // SPELL_HASH_INSTANT_POISON:
2624 case 8679:
2625 case 8680:
2626 case 28428:
2627 case 41189:
2628 case 59242:
2629 if (getSpellInfo()->getEffect(static_cast<uint8_t>(i)) == SPELL_EFFECT_SCHOOL_DAMAGE)
2631 break;
2632 // SPELL_HASH_WOUND_POISON_VII:
2633 case 57975:
2634 case 57978:
2635 // SPELL_HASH_WOUND_POISON_VI:
2636 case 57974:
2637 case 57977:
2638 // SPELL_HASH_WOUND_POISON_V:
2639 case 27188:
2640 case 27189:
2641 // SPELL_HASH_WOUND_POISON_IV:
2642 case 13224:
2643 case 13227:
2644 // SPELL_HASH_WOUND_POISON_III:
2645 case 13223:
2646 case 13226:
2647 // SPELL_HASH_WOUND_POISON_II:
2648 case 13222:
2649 case 13225:
2650 // SPELL_HASH_WOUND_POISON:
2651 case 13218:
2652 case 13219:
2653 case 30984:
2654 case 36974:
2655 case 39665:
2656 case 43461:
2657 case 54074:
2658 case 65962:
2659 if (getSpellInfo()->getEffect(static_cast<uint8_t>(i)) == SPELL_EFFECT_SCHOOL_DAMAGE)
2661 break;
2662 }
2663 }
2664 }
2665 }
2666
2667 return value;
2668}
@ SCHOOL_HOLY
Definition School.hpp:13
@ SPELL_FLAG_IS_POISON
uint32_t getModDamageDonePositive(uint16_t school) const
Definition Player.cpp:1201
int8_t getComboPoints() const
Definition Player.cpp:5361
int32_t getEffectBasePoints(uint8_t idx) const
float getEffectDamageMultiplier(uint8_t idx) const
float getMaxDamage() const
Definition Unit.cpp:1284
uint32_t getMaxPower(PowerType type) const
Definition Unit.cpp:654
void setPower(PowerType type, uint32_t value, bool sendPacket=true, bool skipObjectUpdate=false)
Definition Unit.cpp:547
float getMinDamage() const
Definition Unit.cpp:1281
bool isDazed() const
Definition Unit.cpp:5774
int32_t getCalculatedAttackPower() const
Definition Unit.cpp:1813
int32_t getCalculatedRangedAttackPower() const
Definition Unit.cpp:1822
ItemDamage Damage[MAX_ITEM_PROTO_DAMAGES]
signed char int8_t
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DuelSpellNoMoreValid()

bool Spell::DuelSpellNoMoreValid ( ) const

bool DuelSpellNoMoreValid() Tells if the Spell was being casted while dueling but now the duel is over

Returns
true if Spell is now invalid because the duel is over false if Spell is valid.

Definition at line 2906 of file Spell.Legacy.cpp.

2907{
2908 if (duelSpell && (
2909 (p_caster != nullptr && p_caster->getDuelState() != DUEL_STATE_STARTED) ||
2910 (u_caster != nullptr && u_caster->isPet() && static_cast<Pet*>(u_caster)->getPlayerOwner() && static_cast<Pet*>(u_caster)->getPlayerOwner()->getDuelState() != DUEL_STATE_STARTED)))
2911 return true;
2912 else
2913 return false;
2914}
Definition Pet.h:44
Player * getPlayerOwner() override
Definition Summon.cpp:352
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FillAllFriendlyInArea()

void Spell::FillAllFriendlyInArea ( uint32_t  i,
float  srcx,
float  srcy,
float  srcz,
float  range 
)

Definition at line 247 of file Spell.Legacy.cpp.

248{
249 std::vector<uint64_t>* tmpMap = &m_effectTargets[i];
250 float r = range * range;
251 SpellDidHitResult did_hit_result;
252
253 for (const auto& itr : m_caster->getInRangeObjectsSet())
254 {
255 if (itr)
256 {
257 auto obj = itr;
258 if (!(itr->isCreatureOrPlayer()) || !static_cast<Unit*>(itr)->isAlive())
259 continue;
260
261 if (getSpellInfo()->getTargetCreatureType())
262 {
263 if (!itr->isCreature())
264 continue;
265 CreatureProperties const* inf = static_cast<Creature*>(itr)->GetCreatureProperties();
266 if (!(1 << (inf->Type - 1) & getSpellInfo()->getTargetCreatureType()))
267 continue;
268 }
269
270 if (obj->isInRange(srcx, srcy, srcz, r))
271 {
272 if (worldConfig.terrainCollision.isCollisionEnabled)
273 {
274 bool isInLOS = m_caster->IsWithinLOSInMap(itr);
275
276 if (m_caster->GetMapId() == itr->GetMapId() && !isInLOS)
277 continue;
278 }
279
280 if (u_caster != nullptr)
281 {
282 if (u_caster->isFriendlyTo(itr))
283 {
284 did_hit_result = static_cast<SpellDidHitResult>(DidHit(i, static_cast<Unit*>(itr)));
285 if (did_hit_result == SPELL_DID_HIT_SUCCESS)
286 SafeAddTarget(tmpMap, itr->getGuid());
287 else
288 safeAddMissedTarget(itr->getGuid(), did_hit_result, SPELL_DID_HIT_SUCCESS);
289 }
290 }
291 else //cast from GO
292 {
293 if (g_caster != nullptr && g_caster->getCreatedByGuid() && g_caster->getUnitOwner() != nullptr)
294 {
295 //trap, check not to attack owner and friendly
297 SafeAddTarget(tmpMap, itr->getGuid());
298 }
299 else
300 SafeAddTarget(tmpMap, itr->getGuid());
301 }
302 if (getSpellInfo()->getMaxTargets())
303 if (getSpellInfo()->getMaxTargets() == tmpMap->size())
304 return;
305 }
306 }
307 }
308}
Unit * getUnitOwner() override
uint64_t getCreatedByGuid() const
void SafeAddTarget(std::vector< uint64_t > *tgt, uint64_t guid)
double inf()
Definition g3dmath.cpp:40
Here is the call graph for this function:

◆ FillAllTargetsInArea() [1/3]

void Spell::FillAllTargetsInArea ( float  srcx,
float  srcy,
float  srcz,
uint32_t  ind 
)

Definition at line 170 of file Spell.Legacy.cpp.

171{
172 FillAllTargetsInArea(ind, srcx, srcy, srcz, getEffectRadius(ind));
173}
void FillAllTargetsInArea(uint32_t i, float srcx, float srcy, float srcz, float range)
Here is the call graph for this function:

◆ FillAllTargetsInArea() [2/3]

void Spell::FillAllTargetsInArea ( LocationVector location,
uint32_t  ind 
)

Definition at line 165 of file Spell.Legacy.cpp.

166{
167 FillAllTargetsInArea(ind, location.x, location.y, location.z, getEffectRadius(ind));
168}
Here is the call graph for this function:

◆ FillAllTargetsInArea() [3/3]

void Spell::FillAllTargetsInArea ( uint32_t  i,
float  srcx,
float  srcy,
float  srcz,
float  range 
)

Definition at line 176 of file Spell.Legacy.cpp.

177{
178 std::vector<uint64_t>* tmpMap = &m_effectTargets[i];
179 float r = range * range;
180 SpellDidHitResult did_hit_result;
181
182 for (const auto& itr : m_caster->getInRangeObjectsSet())
183 {
184 if (itr)
185 {
186 auto obj = itr;
187 if (!itr->isCreatureOrPlayer() || !static_cast<Unit*>(itr)->isAlive()) //|| (TO< Creature* >(*itr)->isTotem() && !TO< Unit* >(*itr)->isPlayer())) why shouldn't we fill totems?
188 continue;
189
190 if (p_caster && (itr)->isPlayer() && p_caster->getGroup() && static_cast<Player*>(itr)->getGroup() && static_cast<Player*>(itr)->getGroup() == p_caster->getGroup()) //Don't attack party members!!
191 {
192 //Dueling - AoE's should still hit the target party member if you're dueling with him
193 if (!p_caster->getDuelPlayer() || p_caster->getDuelPlayer() != static_cast<Player*>(itr))
194 continue;
195 }
196 if (getSpellInfo()->getTargetCreatureType())
197 {
198 if (!itr->isCreature())
199 continue;
200 CreatureProperties const* inf = static_cast<Creature*>(itr)->GetCreatureProperties();
201 if (!(1 << (inf->Type - 1) & getSpellInfo()->getTargetCreatureType()))
202 continue;
203 }
204 if (obj->isInRange(srcx, srcy, srcz, r))
205 {
206 if (worldConfig.terrainCollision.isCollisionEnabled)
207 {
208 bool isInLOS = m_caster->IsWithinLOSInMap(itr);
209
210 if (m_caster->GetMapId() == itr->GetMapId() && !isInLOS)
211 continue;
212 }
213
214 if (u_caster != nullptr)
215 {
217 {
218 did_hit_result = static_cast<SpellDidHitResult>(DidHit(i, static_cast<Unit*>(itr)));
219 if (did_hit_result == SPELL_DID_HIT_SUCCESS)
220 SafeAddTarget(tmpMap, itr->getGuid());
221 else
222 safeAddMissedTarget(itr->getGuid(), did_hit_result, SPELL_DID_HIT_SUCCESS);
223 }
224 }
225 else //cast from GO
226 {
227 if (g_caster != nullptr && g_caster->getCreatedByGuid() && g_caster->getUnitOwner() != nullptr)
228 {
229 //trap, check not to attack owner and friendly
231 SafeAddTarget(tmpMap, itr->getGuid());
232 }
233 else
234 SafeAddTarget(tmpMap, itr->getGuid());
235 }
236 if (getSpellInfo()->getMaxTargets())
237 if (getSpellInfo()->getMaxTargets() == tmpMap->size())
238 {
239 return;
240 }
241 }
242 }
243 }
244}
Player * getDuelPlayer() const
Definition Player.cpp:11874
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FillSpecifiedTargetsInArea() [1/2]

void Spell::FillSpecifiedTargetsInArea ( float  srcx,
float  srcy,
float  srcz,
uint32_t  ind,
uint32_t  specification 
)

Definition at line 101 of file Spell.Legacy.cpp.

102{
103 FillSpecifiedTargetsInArea(ind, srcx, srcy, srcz, getEffectRadius(ind), specification);
104}
void FillSpecifiedTargetsInArea(float srcx, float srcy, float srcz, uint32_t ind, uint32_t specification)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FillSpecifiedTargetsInArea() [2/2]

void Spell::FillSpecifiedTargetsInArea ( uint32_t  i,
float  srcx,
float  srcy,
float  srcz,
float  range,
uint32_t  specification 
)

Definition at line 107 of file Spell.Legacy.cpp.

108{
109 std::vector<uint64_t>* tmpMap = &m_effectTargets[i];
110 //IsStealth()
111 float r = range * range;
112 SpellDidHitResult did_hit_result;
113
114 for (const auto& itr : m_caster->getInRangeObjectsSet())
115 {
116 auto obj = itr;
117 // don't add objects that are not units and that are dead
118 if (!obj || !obj->isCreatureOrPlayer() || !static_cast<Unit*>(obj)->isAlive())
119 continue;
120
121 if (getSpellInfo()->getTargetCreatureType())
122 {
123 if (!obj->isCreature())
124 continue;
125 CreatureProperties const* inf = static_cast<Creature*>(obj)->GetCreatureProperties();
126 if (!(1 << (inf->Type - 1) & getSpellInfo()->getTargetCreatureType()))
127 continue;
128 }
129
130 if (obj->isInRange(srcx, srcy, srcz, r))
131 {
132 if (u_caster != nullptr)
133 {
135 {
136 did_hit_result = static_cast<SpellDidHitResult>(DidHit(i, static_cast<Unit*>(itr)));
137 if (did_hit_result != SPELL_DID_HIT_SUCCESS)
138 safeAddMissedTarget(itr->getGuid(), did_hit_result, SPELL_DID_HIT_SUCCESS);
139 else
140 SafeAddTarget(tmpMap, itr->getGuid());
141 }
142
143 }
144 else //cast from GO
145 {
147 {
148 //trap, check not to attack owner and friendly
150 SafeAddTarget(tmpMap, itr->getGuid());
151 }
152 else
153 SafeAddTarget(tmpMap, itr->getGuid());
154 }
155 if (getSpellInfo()->getMaxTargets())
156 {
157 if (getSpellInfo()->getMaxTargets() >= tmpMap->size())
158 {
159 return;
160 }
161 }
162 }
163 }
164}
Here is the call graph for this function:

◆ FillTargetMap()

void Spell::FillTargetMap ( uint32_t  i)
Todo:
arcemu, doesn't support summon slots?

Definition at line 39 of file SpellTarget.Legacy.cpp.

40{
41 //Spell::prepare() has already a m_caster->IsInWorld() check so if now the caster is no more in world something bad happened.
42 if (!m_caster->IsInWorld())
43 return;
44
47
49 return;
50 if (TargetType == SPELL_TARGET_NO_OBJECT) //summon spells that appear infront of caster
51 {
53 return;
54 }
55
56 //always add this guy :P
58 {
59 Object* target = nullptr;
64
65 // If target was not found, try unit
66 if (target == nullptr)
68
69 AddTarget(i, TargetType, target);
70 }
71
74 if (TargetType & (SPELL_TARGET_AREA | SPELL_TARGET_AREA_SELF)) //targetted aoe
76 ///\todo arcemu, doesn't support summon slots?
77 /*if (TargetType & SPELL_TARGET_OBJECT_CURTOTEMS && u_caster != NULL)
78 for (uint32_t i=1; i<5; ++i) //totem slots are 1, 2, 3, 4
79 AddTarget(i, TargetType, u_caster->m_summonslot[i]);*/
83 {
84 WoWGuid wowGuid;
86 if (wowGuid.isPet())
87 {
88 Pet* p = m_caster->getWorldMap()->getPet(wowGuid.getGuidLowPart());
89 if (p != nullptr)
91 }
92 }
93 //targets party, not raid
95 {
96 if (p_caster == nullptr && !m_caster->isPet() && (!m_caster->isCreature() || !m_caster->isTotem()))
98 else
99 AddPartyTargets(i, TargetType, getEffectRadius(i), m_spellInfo->getMaxTargets()); //players/pets/totems
100 }
102 {
103 if (p_caster == nullptr && !m_caster->isPet() && (!m_caster->isCreature() || !m_caster->isTotem()))
105 else
107 }
110 //target cone
113
116}
@ SPELL_TARGET_NOT_IMPLEMENTED
Definition SpellTarget.h:45
@ SPELL_TARGET_NO_OBJECT
Definition SpellTarget.h:46
@ SPELL_TARGET_OBJECT_PETOWNER
Definition SpellTarget.h:34
#define false
Definition StormPort.h:33
uint32_t getMaxTargets() const
void HandleTargetNoObject()
void AddRaidTargets(uint32_t i, uint32_t TargetType, float r, uint32_t maxtargets, bool partylimit=false)
void AddAOETargets(uint32_t i, uint32_t TargetType, float r, uint32_t maxtargets)
void AddPartyTargets(uint32_t i, uint32_t TargetType, float r, uint32_t maxtargets)
void AddChainTargets(uint32_t i, uint32_t TargetType, float r, uint32_t maxtargets)
void AddScriptedOrSpellFocusTargets(uint32_t i, uint32_t TargetType, float r, uint32_t maxtargets)
void AddConeTargets(uint32_t i, uint32_t TargetType, float r, uint32_t maxtargets)
Unit * getUnitOwner() override
Definition Summon.cpp:342
bool isPet() const
Definition WoWGuid.h:300
Here is the call graph for this function:
Here is the caller graph for this function:

◆ finish()

void Spell::finish ( bool  successful = true)

Definition at line 1076 of file Spell.cpp.

1077{
1079 return;
1080
1082
1083 // Caster could be nullptr at this point
1084 if (getCaster() == nullptr)
1085 {
1086 delete this;
1087 return;
1088 }
1089
1090 // Clear spell cooldown if player has cooldown cheat
1091 if (!m_triggeredSpell && getPlayerCaster() != nullptr && getPlayerCaster()->m_cheats.hasCooldownCheat)
1093
1094 // No need to do anything else on failed spells
1095 if (!successful)
1096 {
1098 return;
1099 }
1100
1101 // Unit spell script hooks
1102 if (getUnitCaster() != nullptr)
1103 {
1104 if (getUnitCaster()->IsInWorld() && getUnitCaster()->isCreature() && dynamic_cast<Creature*>(getUnitCaster())->GetScript())
1105 dynamic_cast<Creature*>(getUnitCaster())->GetScript()->OnCastSpell(getSpellInfo()->getId());
1106
1108 {
1109 for (const auto& uniqueTarget : m_uniqueHittedTargets)
1110 {
1111 auto* const targetUnit = getUnitCaster()->getWorldMapUnit(uniqueTarget.first);
1112 if (targetUnit == nullptr)
1113 continue;
1114
1115 if (getUnitCaster()->IsInWorld() && getUnitCaster()->isCreature() && dynamic_cast<Creature*>(getUnitCaster())->GetScript())
1116 dynamic_cast<Creature*>(getUnitCaster())->GetScript()->OnSpellHitTarget(targetUnit, getSpellInfo());
1117
1118 if (!targetUnit->isCreature())
1119 continue;
1120
1121 auto* const targetCreature = dynamic_cast<Creature*>(targetUnit);
1122 if (targetCreature->IsInWorld() && targetCreature->isCreature() && targetCreature->GetScript())
1123 targetCreature->GetScript()->OnHitBySpell(getSpellInfo()->getId(), getUnitCaster());
1124 }
1125 }
1126
1127 u_caster->m_canMove = true;
1128 }
1129
1130 // Recheck used spell modifiers
1132
1133 if (getPlayerCaster() != nullptr)
1134 {
1135 if (getSpellInfo()->getAttributes() & ATTRIBUTES_STOP_ATTACK && getPlayerCaster()->isAttacking())
1136 {
1138 getPlayerCaster()->smsg_AttackStop(getPlayerCaster()->getWorldMapUnit(getPlayerCaster()->getTargetGuid()));
1139 getPlayerCaster()->sendPacket(SmsgCancelCombat().serialise().get());
1140 }
1141
1142 if (m_Delayed)
1143 {
1144 auto target = getPlayerCaster()->getWorldMapUnit(getPlayerCaster()->getChannelObjectGuid());
1145 if (target == nullptr)
1146 target = getPlayerCaster()->getWorldMapUnit(getPlayerCaster()->getTargetGuid());
1147
1148 if (target != nullptr)
1149 target->removeAllAurasByIdForGuid(getSpellInfo()->getId(), getCaster()->getGuid());
1150 }
1151
1152 if (getSpellInfo()->hasEffect(SPELL_EFFECT_SUMMON_OBJECT))
1154
1155 // Clear combo points before spell procs
1156 if (m_requiresCP && !GetSpellFailed())
1157 {
1158 // Save used combo point count for some proc spells
1160
1162 }
1163 }
1164
1165 // Handle procs for each target
1166 Unit* targetUnit = nullptr;
1167 if (m_targetProcFlags != 0)
1168 {
1169 // Handle each target's procs to caster
1170 for (const auto& uniqueTarget : m_uniqueHittedTargets)
1171 {
1172 // Check if this target has already handled procs
1173 if (m_doneTargetProcs.find(uniqueTarget.first) != m_doneTargetProcs.end())
1174 continue;
1175
1176 targetUnit = getCaster()->getWorldMapUnit(uniqueTarget.first);
1177 if (targetUnit == nullptr)
1178 continue;
1179
1180 const auto targetProcFlags = m_targetProcFlags | m_casterDamageInfo.victimProcFlags;
1181 targetUnit->handleProc(targetProcFlags, getUnitCaster(), getSpellInfo(), uniqueTarget.second, m_triggeredSpell, PROC_EVENT_DO_ALL, m_triggeredByAura);
1182 }
1183 }
1184
1185 // Handle caster procs
1186 targetUnit = nullptr;
1187 if (getUnitCaster() != nullptr && m_casterProcFlags != 0)
1188 {
1189 // Handle caster's procs to each target
1190 for (const auto& uniqueTarget : m_uniqueHittedTargets)
1191 {
1193 // If caster is target, remove following proc flags
1194 if (uniqueTarget.first == m_caster->getGuid())
1196
1197 targetUnit = getCaster()->getWorldMapUnit(uniqueTarget.first);
1198 if (targetUnit == nullptr)
1199 continue;
1200
1201 getUnitCaster()->handleProc(casterProcFlags, targetUnit, getSpellInfo(), uniqueTarget.second, m_triggeredSpell, PROC_EVENT_DO_TARGET_PROCS_ONLY, m_triggeredByAura);
1202 }
1203
1204 // Use victim only if there was one target
1205 if (m_uniqueHittedTargets.size() == 1)
1206 targetUnit = getCaster()->getWorldMapUnit(m_uniqueHittedTargets.front().first);
1207 else
1208 targetUnit = nullptr;
1209
1210 // Handle caster's self procs
1211 const auto casterProcFlags = m_casterProcFlags | m_casterDamageInfo.attackerProcFlags;
1213 }
1214
1215 // QuestMgr spell hooks and achievement calls
1216 if (getUnitCaster() != nullptr)
1217 {
1218 // Skip 'on next attack' spells if spell is not triggered
1219 // this will be handled on the actual spell cast
1220 if (!(getSpellInfo()->isOnNextMeleeAttack() && !m_triggeredSpell))
1221 {
1222 uint32_t targetCount = 0;
1223 for (auto& target : m_uniqueHittedTargets)
1224 {
1225 WoWGuid wowGuid;
1226 wowGuid.Init(target.first);
1227 // If target is creature
1228 if (wowGuid.isUnit() && getPlayerCaster() != nullptr && getPlayerCaster()->IsInWorld())
1229 {
1230 ++targetCount;
1231 sQuestMgr.OnPlayerCast(getPlayerCaster(), getSpellInfo()->getId(), target.first);
1232 }
1233#ifdef FT_ACHIEVEMENTS
1234 else if (wowGuid.isPlayer())
1235 {
1236 auto* const targetPlayer = getUnitCaster()->getWorldMapPlayer(target.first);
1237 if (targetPlayer != nullptr)
1238 {
1239 targetPlayer->updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, getSpellInfo()->getId(), 0, 0, u_caster);
1240 targetPlayer->updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, getSpellInfo()->getId(), 0, 0, u_caster);
1241 }
1242 }
1243#endif
1244 }
1245
1246 if (getPlayerCaster() != nullptr && getPlayerCaster()->IsInWorld())
1247 {
1248 if (targetCount == 0)
1249 {
1250 auto guid = getPlayerCaster()->getTargetGuid();
1251 sQuestMgr.OnPlayerCast(getPlayerCaster(), getSpellInfo()->getId(), guid);
1252 }
1253
1254#ifdef FT_ACHIEVEMENTS
1255 // Set target for spell cast achievement only if spell had one target
1256 Object* spellTarget = nullptr;
1257 if (m_uniqueHittedTargets.size() == 1)
1258 spellTarget = getPlayerCaster()->getWorldMapObject(m_uniqueHittedTargets.front().first);
1259
1260 if (spellTarget && spellTarget->isCreatureOrPlayer())
1261 getPlayerCaster()->updateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2, getSpellInfo()->getId(), 0, 0, spellTarget->ToUnit());
1262#endif
1263 }
1264 }
1265 }
1266
1267 // Spell is finished, remove it from traveling spells and delete it on next update tick
1269}
@ EVENT_CREATURE_RESPAWN
Definition EventMgr.h:37
#define sQuestMgr
Definition QuestMgr.h:252
@ PROC_EVENT_DO_CASTER_PROCS_ONLY
@ PROC_EVENT_DO_ALL
@ PROC_EVENT_DO_TARGET_PROCS_ONLY
@ SPELL_EFFECT_SUMMON_OBJECT
@ SPELL_STATE_FINISHED
virtual void OnHitBySpell(uint32_t, Unit *)
CreatureAIScript * GetScript()
Unit * ToUnit()
Definition Object.hpp:397
void clearCooldownForSpell(uint32_t spellId)
Definition Player.cpp:4422
void sendPacket(WorldPacket *packet) override
Definition Player.cpp:3161
void clearComboPoints()
Definition Player.cpp:5420
void eventAttackStop()
Definition Player.cpp:13776
std::set< uint64_t > m_doneTargetProcs
Definition Spell.hpp:319
int8_t m_usedComboPoints
Definition Spell.hpp:303
void smsg_AttackStop(Unit *pVictim)
Definition Unit.cpp:7533
uint32_t m_canMove
Definition Unit.hpp:1328
uint32_t handleProc(uint32_t flag, Unit *Victim, SpellInfo const *CastingSpell, DamageInfo damageInfo, bool isSpellTriggered, ProcEvents procEvent=PROC_EVENT_DO_ALL, Aura *triggeredFromAura=nullptr)
Definition Unit.cpp:11606
bool isUnit() const
Definition WoWGuid.h:299
bool isPlayer() const
Definition WoWGuid.h:290
uint32_t victimProcFlags
uint32_t attackerProcFlags
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GenerateTargets()

bool Spell::GenerateTargets ( SpellCastTargets store_buff)

Definition at line 448 of file SpellTarget.Legacy.cpp.

449{
450 if (u_caster == nullptr || u_caster->getAIInterface() == nullptr || !u_caster->IsInWorld())
451 return false;
452
453 bool result = false;
454
455 for (uint8_t i = 0; i < 3; ++i)
456 {
457 if (m_spellInfo->getEffect(i) == 0)
458 continue;
461
463 {
464 t->addTargetMask(TARGET_FLAG_UNIT);
465 t->setUnitTarget(u_caster->getGuid());
466 result = true;
467 }
468
470 {
471 t->setTargetMask(TARGET_FLAG_SELF);
472 result = true;
473 }
474
476 {
477
479 {
480 if (u_caster->getTargetGuid())
481 {
482 //generate targets for things like arcane missiles trigger, tame pet, etc
484 if (target != nullptr)
485 {
486 if (target->isCreatureOrPlayer())
487 {
488 t->addTargetMask(TARGET_FLAG_UNIT);
489 t->setUnitTarget(target->getGuid());
490 result = true;
491 }
492 else if (target->isGameObject())
493 {
494 t->addTargetMask(TARGET_FLAG_OBJECT);
495 t->setGameObjectTarget(target->getGuid());
496 result = true;
497 }
498 }
499 result = true;
500 }
501 }
502
504 {
506 {
507 //generate targets for things like arcane missiles trigger, tame pet, etc
509 if (target != nullptr)
510 {
511 if (target->isCreatureOrPlayer())
512 {
513 t->addTargetMask(TARGET_FLAG_UNIT);
514 t->setUnitTarget(target->getGuid());
515 result = true;
516 }
517 else if (target->isGameObject())
518 {
519 t->addTargetMask(TARGET_FLAG_OBJECT);
520 t->setGameObjectTarget(target->getGuid());
521 result = true;
522 }
523 }
524 }
525 else if (u_caster->getTargetGuid())
526 {
527 //generate targets for things like arcane missiles trigger, tame pet, etc
529 if (target != nullptr)
530 {
531 if (target->isCreatureOrPlayer())
532 {
533 t->addTargetMask(TARGET_FLAG_UNIT);
534 t->setUnitTarget(target->getGuid());
535 result = true;
536 }
537 else if (target->isGameObject())
538 {
539 t->addTargetMask(TARGET_FLAG_OBJECT);
540 t->setGameObjectTarget(target->getGuid());
541 result = true;
542 }
543 }
544 result = true;
545 }
546 else if (u_caster->isCreature() && u_caster->isTotem())
547 {
549 if (target != nullptr)
550 {
551 t->addTargetMask(TARGET_FLAG_UNIT);
552 t->setUnitTarget(target->getGuid());
553 }
554 }
555 }
556
558 {
560 if (target != nullptr)
561 {
562 t->addTargetMask(TARGET_FLAG_UNIT);
563 t->setUnitTarget(target->getGuid());
564 result = true;
565 }
566 else
567 {
568 t->addTargetMask(TARGET_FLAG_UNIT);
569 t->setUnitTarget(u_caster->getGuid());
570 result = true;
571 }
572 }
573 }
574
576 {
577 //we always use radius(0) for some reason
578 bool isInLOS = false;
579 uint8_t attempts = 0;
580 do
581 {
582 //prevent deadlock
583 ++attempts;
584 if (attempts > 10)
585 return false;
586
588 float ang = Util::getRandomFloat(M_PI_FLOAT * 2);
589 auto lv = LocationVector();
590 lv.x = m_caster->GetPositionX() + (cosf(ang) * r);
591 lv.y = m_caster->GetPositionY() + (sinf(ang) * r);
592 lv.z = m_caster->getMapHeight(LocationVector(lv.x, lv.y, m_caster->GetPositionZ() + 2.0f));
593 t->setDestination(lv);
594 t->setTargetMask(TARGET_FLAG_DEST_LOCATION);
595
596 isInLOS = m_caster->IsWithinLOS(lv);
597 }
598 while (worldConfig.terrainCollision.isCollisionEnabled && !isInLOS);
599 result = true;
600 }
601 else if (TargetType & SPELL_TARGET_AREA) //targetted aoe
602 {
603 //spells like blizzard, rain of fire
605 {
607 if (target)
608 {
610 t->setDestination(target->GetPosition());
611 }
612 result = true;
613 }
614 else
615 {
617 {
619 t->setDestination(u_caster->getAIInterface()->getCurrentTarget()->GetPosition());
620 result = true;
621 }
623 {
625 t->setDestination(u_caster->GetPosition());
626 result = true;
627 }
628 }
629 }
631 {
633 t->setUnitTarget(u_caster->getGuid());
634 t->setSource(u_caster->GetPosition());
635 t->setDestination(u_caster->GetPosition());
636 result = true;
637 }
638
640 {
642 {
643 if (u_caster->getAIInterface()->getCurrentTarget() != nullptr)
644 {
645 t->addTargetMask(TARGET_FLAG_UNIT);
646 t->setUnitTarget(u_caster->getAIInterface()->getCurrentTarget()->getGuid());
647 result = true;
648 }
649 }
650 else
651 {
652 t->addTargetMask(TARGET_FLAG_UNIT);
653 t->setUnitTarget(u_caster->getGuid());
654 result = true;
655 }
656 }
657 //target cone
659 {
660 if (u_caster->getAIInterface()->getCurrentTarget() != nullptr)
661 {
662 t->addTargetMask(TARGET_FLAG_DEST_LOCATION);
663 t->setDestination(u_caster->getAIInterface()->getCurrentTarget()->GetPosition());
664 result = true;
665 }
666 }
667 }
668 return result;
669}
#define M_PI_FLOAT
@ TARGET_FLAG_SOURCE_LOCATION
@ TARGET_FLAG_OBJECT
@ TARGET_FLAG_SELF
@ SPELL_TARGET_ANY_OBJECT
Definition SpellTarget.h:47
@ SPELL_TARGET_AREA_RANDOM
Definition SpellTarget.h:42
Unit * getCurrentTarget() const
uint64_t GetSinglePossibleEnemy(uint32_t i, float prange=0)
uint64_t GetSinglePossibleFriend(uint32_t i, float prange=0)
uint64_t getChannelObjectGuid() const
Definition Unit.cpp:403
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetBaseThreat()

uint32_t Spell::GetBaseThreat ( uint32_t  dmg)
static

Definition at line 1682 of file Spell.Legacy.cpp.

1683{
1684 //there should be a formula to determine what spell cause threat and which don't
1685 return dmg;
1686}

◆ getCaster()

Object * Spell::getCaster ( ) const

Definition at line 5629 of file Spell.cpp.

5630{
5631 return m_caster;
5632}
Here is the caller graph for this function:

◆ getCastTimeLeft()

int32_t Spell::getCastTimeLeft ( ) const

Definition at line 5545 of file Spell.cpp.

5546{
5547 return m_timer;
5548}
Here is the caller graph for this function:

◆ getCorpseTarget()

Corpse * Spell::getCorpseTarget ( ) const

Definition at line 5688 of file Spell.cpp.

5688{ return m_corpseTarget; }

◆ getDestination()

LocationVector Spell::getDestination ( )
inline

Definition at line 190 of file Spell.hpp.

190{ return m_targets.getDestination(); }
Here is the caller graph for this function:

◆ getDuration()

int32_t Spell::getDuration ( )

Definition at line 5910 of file Spell.cpp.

5911{
5912 if (isDurationSet)
5913 return m_duration;
5914
5915 isDurationSet = true;
5916
5917 if (!getSpellInfo()->getDurationIndex())
5918 {
5919 m_duration = -1;
5920 return m_duration;
5921 }
5922
5923 const auto spellDuration = sSpellDurationStore.lookupEntry(getSpellInfo()->getDurationIndex());
5924 if (spellDuration == nullptr)
5925 {
5926 m_duration = -1;
5927 return m_duration;
5928 }
5929
5930 // Duration affected by level
5931 if (getUnitCaster() != nullptr && spellDuration->Duration1 < 0 && spellDuration->Duration2)
5932 {
5933 m_duration = spellDuration->Duration1 + (spellDuration->Duration2 * static_cast<int32_t>(getUnitCaster()->getLevel()));
5934
5935 if (m_duration > 0 && spellDuration->Duration3 > 0 && m_duration > spellDuration->Duration3)
5936 m_duration = spellDuration->Duration3;
5937
5938 if (m_duration < 0)
5939 m_duration = 0;
5940 }
5941
5942 if (m_duration == 0)
5943 m_duration = spellDuration->Duration1;
5944
5945 // Check if duration is affected by combo points
5946 if (getPlayerCaster() != nullptr)
5947 {
5948 if (const auto comboPoints = getPlayerCaster()->getComboPoints())
5949 {
5950 const auto bonus = (comboPoints * (spellDuration->Duration3 - spellDuration->Duration1)) / 5;
5951 if (bonus)
5952 m_duration += bonus;
5953 }
5954 }
5955
5956 if (getUnitCaster() != nullptr && m_duration > 0)
5957 {
5958 // Apply duration modifiers
5960
5961 // Apply haste bonus
5962 if (getSpellInfo()->getAttributesExE() & ATTRIBUTESEXE_HASTE_AFFECTS_DURATION)
5964 }
5965
5966 return m_duration;
5967}
@ ATTRIBUTESEXE_HASTE_AFFECTS_DURATION
@ SPELLMOD_DURATION
SERVER_DECL WDB::WDBContainer< WDB::Structures::SpellDurationEntry > sSpellDurationStore
bool isDurationSet
Definition Spell.hpp:306
int32_t m_duration
Definition Spell.hpp:305
float getModCastSpeed() const
Definition Unit.cpp:1421
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getEffectRadius()

float_t Spell::getEffectRadius ( uint8_t  effectIndex)

Definition at line 5969 of file Spell.cpp.

5970{
5971 if (m_isEffectRadiusSet[effectIndex])
5972 return m_effectRadius[effectIndex];
5973
5974 m_isEffectRadiusSet[effectIndex] = true;
5975 m_effectRadius[effectIndex] = ::GetRadius(sSpellRadiusStore.lookupEntry(getSpellInfo()->getEffectRadiusIndex(effectIndex)));
5976
5977 // If spell has no effect radius set, use spell range instead
5978 // but skip for effect target 87. Otherwise some teleport spells like ICC teleports will target
5979 // all units in infinite range
5980 if (G3D::fuzzyEq(m_effectRadius[effectIndex], 0.f) &&
5981 getSpellInfo()->getEffectImplicitTargetA(effectIndex) != EFF_TARGET_AREA_DESTINATION && getSpellInfo()->getEffectImplicitTargetB(effectIndex) != EFF_TARGET_AREA_DESTINATION)
5982 {
5983 const auto rangeEntry = sSpellRangeStore.lookupEntry(getSpellInfo()->getRangeIndex());
5984 if (rangeEntry != nullptr)
5985 {
5986#if VERSION_STRING < WotLK
5987 m_effectRadius[effectIndex] = rangeEntry->maxRange;
5988#else
5989 const auto effectTargetMask = getSpellInfo()->getRequiredTargetMaskForEffect(effectIndex);
5990 m_effectRadius[effectIndex] = effectTargetMask & SPELL_TARGET_REQUIRE_ATTACKABLE ? rangeEntry->maxRange : rangeEntry->maxRangeFriendly;
5991#endif
5992 }
5993 }
5994
5995 // Apply radius modifiers
5996 if (getUnitCaster() != nullptr)
5998
5999 return m_effectRadius[effectIndex];
6000}
@ EFF_TARGET_AREA_DESTINATION
@ SPELLMOD_RADIUS
SERVER_DECL WDB::WDBContainer< WDB::Structures::SpellRadiusEntry > sSpellRadiusStore
float SERVER_DECL GetRadius(WDB::Structures::SpellRadiusEntry const *radius)
Definition WDBStores.cpp:22
float_t m_effectRadius[MAX_SPELL_EFFECTS]
Definition Spell.hpp:308
bool m_isEffectRadiusSet[MAX_SPELL_EFFECTS]
Definition Spell.hpp:309
bool fuzzyEq(double a, double b)
Definition g3dmath.h:857
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getFullCastTime()

int32_t Spell::getFullCastTime ( ) const

Definition at line 5540 of file Spell.cpp.

5541{
5542 return m_castTime;
5543}
Here is the caller graph for this function:

◆ getGameObjectCaster()

GameObject * Spell::getGameObjectCaster ( ) const

Definition at line 5644 of file Spell.cpp.

5645{
5646 return g_caster;
5647}
Here is the caller graph for this function:

◆ getGameObjectTarget()

GameObject * Spell::getGameObjectTarget ( ) const

Definition at line 5686 of file Spell.cpp.

5686{ return m_gameObjTarget; }
Here is the caller graph for this function:

◆ getItemCaster()

Item * Spell::getItemCaster ( ) const

Definition at line 5649 of file Spell.cpp.

5650{
5651 return i_caster;
5652}
Here is the caller graph for this function:

◆ getItemTarget()

Item * Spell::getItemTarget ( ) const

Definition at line 5679 of file Spell.cpp.

5679{ return m_itemTarget; }

◆ GetMechanic()

uint32_t Spell::GetMechanic ( SpellInfo const sp)
static

Definition at line 1688 of file Spell.Legacy.cpp.

1689{
1690 if (sp->getMechanicsType())
1691 return sp->getMechanicsType();
1692 if (sp->getEffectMechanic(2))
1693 return sp->getEffectMechanic(2);
1694 if (sp->getEffectMechanic(1))
1695 return sp->getEffectMechanic(1);
1696 if (sp->getEffectMechanic(0))
1697 return sp->getEffectMechanic(0);
1698
1699 return 0;
1700}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getPlayerCaster()

Player * Spell::getPlayerCaster ( ) const

Definition at line 5639 of file Spell.cpp.

5640{
5641 return p_caster;
5642}

◆ getPlayerTarget()

Player * Spell::getPlayerTarget ( ) const

Definition at line 5684 of file Spell.cpp.

5684{ return m_playerTarget; }
Here is the caller graph for this function:

◆ getPowerCost()

uint32_t Spell::getPowerCost ( ) const

Definition at line 5552 of file Spell.cpp.

5553{
5554 return m_powerCost;
5555}
Here is the caller graph for this function:

◆ GetSinglePossibleEnemy()

uint64_t Spell::GetSinglePossibleEnemy ( uint32_t  i,
float  prange = 0 
)

Definition at line 310 of file Spell.Legacy.cpp.

311{
312 float r;
313 if (prange)
314 r = prange;
315 else
316 {
318 if (u_caster != nullptr)
319 {
321 }
322 }
323 float srcx = m_caster->GetPositionX(), srcy = m_caster->GetPositionY(), srcz = m_caster->GetPositionZ();
324
325 for (const auto& itr : m_caster->getInRangeObjectsSet())
326 {
327 auto obj = itr;
328 if (!obj || !itr->isCreatureOrPlayer() || !static_cast<Unit*>(itr)->isAlive())
329 continue;
330
331 if (getSpellInfo()->getTargetCreatureType())
332 {
333 if (!itr->isCreature())
334 continue;
335 CreatureProperties const* inf = static_cast<Creature*>(itr)->GetCreatureProperties();
336 if (!(1 << (inf->Type - 1) & getSpellInfo()->getTargetCreatureType()))
337 continue;
338 }
339 if (obj->isInRange(srcx, srcy, srcz, r))
340 {
341 if (u_caster != nullptr)
342 {
343 if (u_caster->isValidTarget(itr, getSpellInfo()) && DidHit(i, static_cast<Unit*>(itr)) == SPELL_DID_HIT_SUCCESS)
344 {
345 return itr->getGuid();
346 }
347 }
348 else //cast from GO
349 {
351 {
352 //trap, check not to attack owner and friendly
354 {
355 return itr->getGuid();
356 }
357 }
358 }
359 }
360 }
361 return 0;
362}
float custom_base_range_or_radius_sqr
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetSinglePossibleFriend()

uint64_t Spell::GetSinglePossibleFriend ( uint32_t  i,
float  prange = 0 
)

Definition at line 364 of file Spell.Legacy.cpp.

365{
366 float r;
367 if (prange)
368 r = prange;
369 else
370 {
372 if (u_caster != nullptr)
373 {
375 }
376 }
377 float srcx = m_caster->GetPositionX(), srcy = m_caster->GetPositionY(), srcz = m_caster->GetPositionZ();
378
379 for (const auto& itr : m_caster->getInRangeObjectsSet())
380 {
381 auto obj = itr;
382 if (!obj || !itr->isCreatureOrPlayer() || !static_cast<Unit*>(itr)->isAlive())
383 continue;
384 if (getSpellInfo()->getTargetCreatureType())
385 {
386 if (!itr->isCreature())
387 continue;
388 CreatureProperties const* inf = static_cast<Creature*>(itr)->GetCreatureProperties();
389 if (!(1 << (inf->Type - 1) & getSpellInfo()->getTargetCreatureType()))
390 continue;
391 }
392 if (obj->isInRange(srcx, srcy, srcz, r))
393 {
394 if (u_caster != nullptr)
395 {
396 if (u_caster->isFriendlyTo(itr) && DidHit(i, static_cast<Unit*>(itr)) == SPELL_DID_HIT_SUCCESS)
397 {
398 return itr->getGuid();
399 }
400 }
401 else //cast from GO
402 {
404 {
405 //trap, check not to attack owner and friendly
407 {
408 return itr->getGuid();
409 }
410 }
411 }
412 }
413 }
414 return 0;
415}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getSource()

LocationVector Spell::getSource ( )
inline

Definition at line 191 of file Spell.hpp.

191{ return m_targets.getSource(); }
LocationVector getSource() const

◆ GetSpellFailed()

bool Spell::GetSpellFailed ( ) const

Spell state's Spell failed

Definition at line 2916 of file Spell.Legacy.cpp.

2917{
2918 return m_Spell_Failed;
2919}
Here is the caller graph for this function:

◆ getSpellInfo()

SpellInfo const * Spell::getSpellInfo ( ) const

Definition at line 5789 of file Spell.cpp.

5790{
5792}

◆ getState()

uint32_t Spell::getState ( ) const

Definition at line 2901 of file Spell.Legacy.cpp.

2902{
2903 return m_spellState;
2904}
Here is the caller graph for this function:

◆ getTargetConstraintCreature()

Creature * Spell::getTargetConstraintCreature ( ) const

Definition at line 5700 of file Spell.cpp.

Creature * m_targetConstraintCreature
Definition Spell.hpp:212
Here is the caller graph for this function:

◆ getTargetConstraintGameObject()

GameObject * Spell::getTargetConstraintGameObject ( ) const

Definition at line 5703 of file Spell.cpp.

GameObject * m_targetConstraintGameObject
Definition Spell.hpp:213

◆ getTriggeredByAura()

Aura * Spell::getTriggeredByAura ( ) const

Definition at line 5841 of file Spell.cpp.

5842{
5843 return m_triggeredByAura;
5844}
Here is the caller graph for this function:

◆ GetType()

uint32_t Spell::GetType ( )

Definition at line 2729 of file Spell.Legacy.cpp.

2729{ return (getSpellInfo()->getDmgClass() == SPELL_DMG_TYPE_NONE ? SPELL_DMG_TYPE_MAGIC : getSpellInfo()->getDmgClass()); }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getUnitCaster()

Unit * Spell::getUnitCaster ( ) const

Definition at line 5634 of file Spell.cpp.

5635{
5636 return u_caster;
5637}

◆ getUnitTarget()

Unit * Spell::getUnitTarget ( ) const

Definition at line 5682 of file Spell.cpp.

5682{ return m_unitTarget; }

◆ getUsedComboPoints()

int8_t Spell::getUsedComboPoints ( ) const

Definition at line 5846 of file Spell.cpp.

5847{
5848 return m_usedComboPoints;
5849}

◆ HandleAddAura()

void Spell::HandleAddAura ( uint64_t  guid)

Definition at line 1242 of file Spell.Legacy.cpp.

1243{
1244 Unit* Target = nullptr;
1245
1246 auto itr = m_pendingAuras.find(guid);
1247
1248 if (itr == m_pendingAuras.end() || itr->second.aur == nullptr)
1249 return;
1250
1251 //If this aura isn't added correctly it MUST be deleted
1252 auto&& aur = std::move(itr->second.aur);
1253
1254 if (u_caster && u_caster->getGuid() == guid)
1255 Target = u_caster;
1256 else if (m_caster->IsInWorld())
1257 Target = m_caster->getWorldMap()->getUnit(guid);
1258
1259 if (Target == nullptr)
1260 {
1261 return;
1262 }
1263
1264 if (getUnitCaster() != nullptr)
1265 {
1266 if (getUnitCaster()->isFriendlyTo(Target))
1267 {
1269 }
1270 else if (!(getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_NO_INITIAL_AGGRO))
1271 {
1272 // Send initial threat
1273 if (Target->isCreature())
1275
1276 // Target should enter combat when aura is added on target
1278
1279 // Add real threat
1280 if (Target->getThreatManager().canHaveThreatList())
1281 Target->getThreatManager().addThreat(getUnitCaster(), 1.f, getSpellInfo(), false, false, this);
1282 }
1283 }
1284
1285 // Applying an aura to a flagged target will cause you to get flagged.
1286 // self casting doesn't flag himself.
1287 if (Target->isPlayer() && p_caster && p_caster != static_cast<Player*>(Target))
1288 {
1289 if (static_cast<Player*>(Target)->isPvpFlagSet())
1290 {
1291 if (p_caster->isPlayer() && !p_caster->isPvpFlagSet())
1293 else
1295 }
1296 }
1297
1298 // remove any auras with same type
1299 if (getSpellInfo()->custom_BGR_one_buff_on_target > 0)
1300 {
1301 Target->removeAllAurasBySpellType(static_cast<SpellTypes>(getSpellInfo()->custom_BGR_one_buff_on_target), m_caster->getGuid(), getSpellInfo()->getId());
1302 }
1303
1304 uint32_t spellid = 0;
1305
1306 if ((getSpellInfo()->getMechanicsType() == MECHANIC_INVULNARABLE && getSpellInfo()->getId() != 25771) || getSpellInfo()->getId() == 31884) // Cast spell Forbearance
1307 {
1308 if (getSpellInfo()->getId() != 31884)
1309 spellid = 25771;
1310
1311 if (Target->isPlayer())
1312 {
1314 static_cast<Player*>(Target)->m_avengingWrath = false;
1315 }
1316 }
1317 else if (getSpellInfo()->getMechanicsType() == MECHANIC_HEALING && getSpellInfo()->getId() != 11196) // Cast spell Recently Bandaged
1318 spellid = 11196;
1319 else if (getSpellInfo()->getMechanicsType() == MECHANIC_SHIELDED && getSpellInfo()->getId() != 6788) // Cast spell Weakened Soul
1320 spellid = 6788;
1321 else if (getSpellInfo()->getId() == 45438) // Cast spell Hypothermia
1322 spellid = 41425;
1323 else
1324 {
1325 switch (getSpellInfo()->getId())
1326 {
1327 //SPELL_HASH_HEROISM
1328 case 23682:
1329 case 23689:
1330 case 32182:
1331 case 32927:
1332 case 32955:
1333 case 37471:
1334 case 39200:
1335 case 65983:
1336 spellid = 57723;
1337 break;
1338 //SPELL_HASH_BLOODLUST
1339 case 2825:
1340 case 6742:
1341 case 16170:
1342 case 21049:
1343 case 23951:
1344 case 24185:
1345 case 27689:
1346 case 28902:
1347 case 33555:
1348 case 37067:
1349 case 37309:
1350 case 37310:
1351 case 37472:
1352 case 37599:
1353 case 41185:
1354 case 43578:
1355 case 45584:
1356 case 50730:
1357 case 54516:
1358 case 65980:
1359 spellid = 57724;
1360 break;
1361 //SPELL_HASH_STEALTH
1362 case 1784:
1363 case 1785:
1364 case 1786:
1365 case 1787:
1366 case 8822:
1367 case 30831:
1368 case 30991:
1369 case 31526:
1370 case 31621:
1371 case 32199:
1372 case 32615:
1373 case 34189:
1374 case 42347:
1375 case 42866:
1376 case 42943:
1377 case 52188:
1378 case 58506:
1379 {
1380 uint32_t masterOfSubtlety[] =
1381 {
1382 //SPELL_HASH_MASTER_OF_SUBTLETY
1383 31221,
1384 31222,
1385 31223,
1386 31665,
1387 31666,
1388 0
1389 };
1390
1391 if (Target->hasAurasWithId(masterOfSubtlety))
1392 spellid = 31665;
1393 } break;
1394 case 62124:
1395 {
1396 uint32_t vindication[] =
1397 {
1398 //SPELL_HASH_VINDICATION
1399 67,
1400 9452,
1401 26016,
1402 26017,
1403 36002,
1404 0
1405 };
1406
1407 if (u_caster)
1408 {
1409 if (const auto* vindicationAur = u_caster->getAuraWithId(vindication))
1410 {
1411 const uint8_t rank = vindicationAur->getSpellInfo()->hasSpellRanks()
1412 ? vindicationAur->getSpellInfo()->getRankInfo()->getRank()
1413 : 1;
1414 spellid = rank == 2 ? 26017 : 67;
1415 }
1416 }
1417 } break;
1418 case 5229:
1419 {
1420 uint32_t kingOfTheJungle[] =
1421 {
1422 //SPELL_HASH_KING_OF_THE_JUNGLE
1423 48492,
1424 48494,
1425 48495,
1426 51178,
1427 51185,
1428 0
1429 };
1430
1432 p_caster->hasAurasWithId(kingOfTheJungle))
1433 {
1434 const auto spellInfo = sSpellMgr.getSpellInfo(51185);
1435 if (!spellInfo)
1436 {
1437 return;
1438 }
1439
1440 Spell* spell = sSpellMgr.newSpell(p_caster, spellInfo, true, nullptr);
1441
1442 if (const auto* kotjAur = p_caster->getAuraWithId(kingOfTheJungle))
1443 {
1444 const uint8_t rank = kotjAur->getSpellInfo()->hasSpellRanks()
1445 ? kotjAur->getSpellInfo()->getRankInfo()->getRank()
1446 : 1;
1447 spell->forced_basepoints->set(0, rank * 5);
1448 }
1449 SpellCastTargets targets(p_caster->getGuid());
1450 spell->prepare(&targets);
1451 }
1452 } break;
1453 case 19574:
1454 {
1455 if (u_caster != nullptr)
1456 {
1457 uint32_t theBeastWithin[] =
1458 {
1459 //SPELL_HASH_THE_BEAST_WITHIN
1460 34471,
1461 34692,
1462 38373,
1463 50098,
1464 70029,
1465 0
1466 };
1467
1468 if (u_caster->hasAurasWithId(theBeastWithin))
1469 u_caster->castSpell(u_caster, 34471, true);
1470 }
1471 } break;
1472 // SPELL_HASH_RAPID_KILLING
1473 case 34948:
1474 case 34949:
1475 case 35098:
1476 case 35099:
1477 {
1478 if (u_caster != nullptr)
1479 {
1480 uint32_t rapidRecuperation[] =
1481 {
1482 //SPELL_HASH_RAPID_RECUPERATION
1483 53228,
1484 53232,
1485 56654,
1486 58882,
1487 58883,
1488 64180,
1489 64181,
1490 0
1491 };
1492
1493 if (u_caster->hasAurasWithId(rapidRecuperation))
1494 spellid = 56654;
1495 }
1496 } break;
1497 }
1498 }
1499
1500 switch (getSpellInfo()->getId())
1501 {
1502 // SPELL_HASH_CLEARCASTING:
1503 case 12536:
1504 case 16246:
1505 case 16870:
1506 case 67210:
1507 // SPELL_HASH_PRESENCE_OF_MIND:
1508 case 12043:
1509 case 29976:
1510 {
1511 uint32_t arcanePotency[] =
1512 {
1513 //SPELL_HASH_ARCANE_POTENCY
1514 24544,
1515 31571,
1516 31572,
1517 33421,
1518 33713,
1519 57529,
1520 57531,
1521 0
1522 };
1523 if (const auto* arcPotencyAur = Target->getAuraWithId(arcanePotency))
1524 {
1525 const uint8_t rank = arcPotencyAur->getSpellInfo()->hasSpellRanks()
1526 ? arcPotencyAur->getSpellInfo()->getRankInfo()->getRank()
1527 : 1;
1528 spellid = rank == 1 ? 57529 : 57531;
1529 }
1530 }
1531 break;
1532 }
1533
1534 if (spellid)
1535 {
1536 const auto spellInfo = sSpellMgr.getSpellInfo(spellid);
1537 if (!spellInfo)
1538 {
1539 return;
1540 }
1541
1542 Spell* spell = sSpellMgr.newSpell(u_caster, spellInfo, true, nullptr);
1543
1544 uint32_t masterOfSubtlety[] =
1545 {
1546 //SPELL_HASH_MASTER_OF_SUBTLETY
1547 31221,
1548 31222,
1549 31223,
1550 31665,
1551 31666,
1552 0
1553 };
1554
1555 if (spellid == 31665 && Target->hasAurasWithId(masterOfSubtlety))
1556 spell->forced_basepoints->set(0, Target->getAuraWithId(masterOfSubtlety)->getSpellInfo()->getEffectBasePoints(0));
1557
1558 SpellCastTargets targets(Target->getGuid());
1559 spell->prepare(&targets);
1560 }
1561
1562 // avoid map corruption (this is impossible, btw)
1563 if (Target->GetInstanceID() != m_caster->GetInstanceID())
1564 {
1565 return;
1566 }
1567
1568 Target->addAura(std::move(aur)); // the real spell is added last so the modifier is removed last
1569}
@ EVENT_PLAYER_AVENGING_WRATH
Definition EventMgr.h:90
@ ATTRIBUTESEX_NO_INITIAL_AGGRO
@ MECHANIC_HEALING
@ MECHANIC_SHIELDED
@ MECHANIC_INVULNARABLE
SpellTypes
Definition SpellTypes.hpp:9
void onHostileAction(Unit *pUnit, SpellInfo const *spellInfo=nullptr, bool ignoreThreatRedirects=false)
SpellInfo const * getSpellInfo() const
void takeCombatAction(Unit *initiater, bool friendlyCombat=false, bool skipInitialDelay=false)
int32_t GetInstanceID()
Definition Object.hpp:664
void avengingWrath()
Definition Player.hpp:2247
void setPvpFlag() override
Definition Player.cpp:9790
void togglePvP()
Definition Player.cpp:8343
bool isPvpFlagSet() const override
Definition Player.cpp:9781
bool hasSpellRanks() const
SpellCastResult prepare(SpellCastTargets *targets)
Definition Spell.cpp:255
void addThreat(Unit *target, float amount, SpellInfo const *spell=nullptr, bool ignoreModifiers=false, bool ignoreRedirects=false, Spell *castingSpell=nullptr)
static bool canHaveThreatList(Unit const *who)
SpellCastResult castSpell(uint64_t targetGuid, uint32_t spellId, bool triggered=false)
Definition Unit.cpp:3564
ThreatManager & getThreatManager()
Definition Unit.hpp:1190
void addAura(std::unique_ptr< Aura > aur)
Definition Unit.cpp:4538
void removeAllAurasBySpellType(SpellTypes type, uint64_t casterGuid=0, uint32_t skipSpellId=0)
Definition Unit.cpp:5394
Here is the call graph for this function:
Here is the caller graph for this function:

◆ handleHittedEffect()

void Spell::handleHittedEffect ( const uint64_t  targetGuid,
uint8_t  effIndex,
int32_t  effDamage,
bool  reCheckTarget = false 
)

Definition at line 860 of file Spell.cpp.

861{
862 // If duel has ended before spell cast was finished, do not handle this target and effect
863 // but do not cancel entire spell
864 // i.e AoE spells can still hit other targets
866 return;
867
868 if (reCheckTarget)
869 _updateTargetPointers(targetGuid);
870
871 // TODO: in the future, consider having two damage variables; one for integer and one for float
872 damage = effDamage;
873
874 // Skip auras here
875 // TODO: confirm if instant kill spells should skip combat (atm needed for .kill command)
876 if (!getSpellInfo()->doesEffectApplyAura(effIndex) && getUnitCaster() != nullptr && getUnitTarget() != nullptr && getUnitCaster() != getUnitTarget()
877 && getSpellInfo()->getEffect(effIndex) != SPELL_EFFECT_INSTANT_KILL)
878 {
879 if (getUnitCaster()->isFriendlyTo(getUnitTarget()))
880 {
882 }
883 else if (!(getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_NO_INITIAL_AGGRO))
884 {
885 // Add initial threat
886 // Real threat is sent in damage code, in heal code or in apply aura code
887 if (getUnitTarget()->isCreature())
889
890 // Target should enter combat when spell lands on target
892 }
893 }
894
895 // Clear DamageInfo before effect
898 isTargetDamageInfoSet = false;
899 isForcedCrit = false;
900
901 const auto effectId = getSpellInfo()->getEffect(effIndex);
902 if (effectId >= TOTAL_SPELL_EFFECTS)
903 {
904 sLogger.failure("Spell::handleHittedEffect : Unknown spell effect {} in spell id {}, index {}", effectId, getSpellInfo()->getId(), effIndex);
905 return;
906 }
907
908 sLogger.debugFlag(AscEmu::Logging::LF_SPELL, "Spell::handleHittedEffect : Spell effect {}, spell id {}, damage {}", effectId, getSpellInfo()->getId(), damage);
909
910 const auto scriptResult = sScriptMgr.callScriptedSpellBeforeSpellEffect(this, effIndex);
911
912 // Check if spell is forced to have critical effect on this target
913 for (const auto& critGuid : m_critTargets)
914 {
915 if (critGuid == targetGuid)
916 {
917 isForcedCrit = true;
918 break;
919 }
920 }
921
922 // Call effect handler
924 (*this.*SpellEffectsHandler[effectId])(effIndex);
925
926 sScriptMgr.callScriptedSpellAfterSpellEffect(this, effIndex);
927
928 // Create proc events
930 {
931 // Add the DamageInfo to target vector if it was set
932 for (auto& uniqueTarget : m_uniqueHittedTargets)
933 {
934 if (uniqueTarget.first == targetGuid)
935 uniqueTarget.second = m_targetDamageInfo;
936 }
937 }
938
939 // Check if target's procs have been handled in spell effects
940 // If not, they will be processed in Spell::finish
941 // Caster procs are also handled in Spell::finish
943 m_doneTargetProcs.insert(targetGuid);
944
945 if (m_uniqueHittedTargets.size() == 1)
946 {
947 // If spell has only this target, use full DamageInfo for caster's DamageInfo
950 }
951 else
952 {
953 // If spell has multiple targets, just check if the spell critted for this target
956 }
957
958 // Legacy script hook
960}
@ PROC_NULL
Definition ProcFlags.hpp:12
@ SPELL_EFFECT_INSTANT_KILL
@ TOTAL_SPELL_EFFECTS
pSpellEffect SpellEffectsHandler[TOTAL_SPELL_EFFECTS]
virtual void DoAfterHandleEffect(Unit *target, uint32_t i)
void _updateTargetPointers(const uint64_t targetGuid)
Definition Spell.cpp:6158
DamageInfo m_targetDamageInfo
Definition Spell.hpp:313
bool isTargetDamageInfoSet
Definition Spell.hpp:314
bool isForcedCrit
Definition Spell.hpp:330
bool isCritical
Here is the call graph for this function:
Here is the caller graph for this function:

◆ handleHittedTarget()

void Spell::handleHittedTarget ( const uint64_t  targetGuid,
uint8_t  effIndex 
)

Definition at line 808 of file Spell.cpp.

809{
810 const auto travelTime = _getSpellTravelTimeForTarget(targetGuid);
811 if (travelTime < 0)
812 return;
813
814 _updateTargetPointers(targetGuid);
815 const auto effDamage = calculateEffect(effIndex);
816
817 // Enter combat or keep combat alive if spell had at least one target that was either
818 // a) hostile
819 // b) friendly who was in combat
820 // TODO: confirm if instant kill spells should skip combat (atm needed for .kill command)
821 if (getUnitCaster() != nullptr && getUnitTarget() != nullptr && getUnitCaster()->getGuid() != getUnitTarget()->getGuid()
822 && getSpellInfo()->getEffect(effIndex) != SPELL_EFFECT_INSTANT_KILL)
823 {
824 // Combat is applied instantly to caster if spell had cast time and target is hostile
825 // Instant spells on hostile targets and all spells on friendly targets will have combat delayed
826 if (getUnitCaster()->isFriendlyTo(getUnitTarget()))
828 else if (!(getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_NO_INITIAL_AGGRO))
830 }
831
832 // If effect applies an aura, create it instantly but add it later to target
833 if (getSpellInfo()->doesEffectApplyAura(effIndex))
834 {
835 handleHittedEffect(targetGuid, effIndex, effDamage);
836
837 // Add travel time to aura
838 auto itr = m_pendingAuras.find(targetGuid);
839 if (itr != m_pendingAuras.end())
840 itr->second.travelTime = Util::float2int32(travelTime);
841
842 return;
843 }
844
845 if (travelTime == 0.0f)
846 {
847 handleHittedEffect(targetGuid, effIndex, effDamage);
848 }
849 else
850 {
851 HitSpellEffect hitEffect;
852 hitEffect.damage = effDamage;
853 hitEffect.effIndex = effIndex;
854 hitEffect.travelTime = Util::float2int32(travelTime);
855
856 m_hitEffects.insert(std::make_pair(targetGuid, hitEffect));
857 }
858}
void onHostileAction(Unit *victim, bool skipInitialDelay=false)
void onFriendlyAction(Unit *target, bool skipInitialDelay=false)
void handleHittedEffect(const uint64_t targetGuid, uint8_t effIndex, int32_t effDamage, bool reCheckTarget=false)
Definition Spell.cpp:860
int32_t getFullCastTime() const
Definition Spell.cpp:5540
float_t _getSpellTravelTimeForTarget(uint64_t guid) const
Definition Spell.cpp:6267
Here is the call graph for this function:
Here is the caller graph for this function:

◆ handleMissedEffect()

void Spell::handleMissedEffect ( SpellTargetMod const  missedTarget,
bool  reCheckTarget = false 
)

Definition at line 1046 of file Spell.cpp.

1047{
1048 if (reCheckTarget)
1049 _updateTargetPointers(missedTarget.targetGuid);
1050
1051 // Spell was not reflected and it did not hit target
1052 if (getUnitTarget() != nullptr)
1053 {
1054 if (getUnitCaster() != nullptr)
1055 {
1056 if (getUnitCaster()->isFriendlyTo(getUnitTarget()))
1057 {
1059 }
1060 else if (!(getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_NO_INITIAL_AGGRO))
1061 {
1062 // Let target creature know that someone tried to cast spell on it
1063 if (getUnitTarget()->isCreature())
1065
1066 // Target should enter combat when spell lands on target
1068 }
1069 }
1070
1071 // Call scripted after spell missed hook
1072 sScriptMgr.callScriptedSpellAfterMiss(this, getUnitTarget());
1073 }
1074}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ handleMissedTarget()

void Spell::handleMissedTarget ( SpellTargetMod const  missedTarget)

Definition at line 962 of file Spell.cpp.

963{
964 // No need to handle this target if it was in evade mode
965 if (missedTarget.hitResult == SPELL_DID_HIT_EVADE)
966 return;
967
968 const auto didReflect = missedTarget.hitResult == SPELL_DID_HIT_REFLECT && missedTarget.extendedHitResult == SPELL_DID_HIT_SUCCESS;
969
970 auto travelTime = _getSpellTravelTimeForTarget(missedTarget.targetGuid);
971 if (travelTime < 0)
972 return;
973
974 _updateTargetPointers(missedTarget.targetGuid);
975
976 // Enter combat or keep combat alive if spell had at least one target that was either
977 // a) hostile
978 // b) friendly who was in combat
979 if (getUnitCaster() != nullptr && getUnitTarget() != nullptr)
980 {
981 // Combat is applied instantly to caster if spell had cast time and target is hostile
982 // Instant spells on hostile targets and all spells on friendly targets will have combat delayed
983 if (getUnitCaster()->isFriendlyTo(getUnitTarget()))
985 else if (!(getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_NO_INITIAL_AGGRO))
987 }
988
989 // If there is no distance between caster and target, handle effect instantly
990 if (travelTime == 0.0f)
991 {
992 if (didReflect)
993 {
994 const auto guid = m_caster->getGuid();
996
997 // Process each effect from the spell on the original caster
998 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
999 {
1000 if (getSpellInfo()->getEffect(i) != 0)
1002 }
1003 }
1004 else
1005 {
1006 // Spell was not reflected and it did not hit target
1007 handleMissedEffect(missedTarget);
1008 }
1009 }
1010 else
1011 {
1012 if (didReflect)
1013 {
1014 const auto guid = m_caster->getGuid();
1016
1017 // Reflected projectiles move back 4x faster
1018 travelTime *= 1.25f;
1019
1020 // Process each effect from the spell on the original caster
1021 for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
1022 {
1023 if (getSpellInfo()->getEffect(i) != 0)
1024 {
1025 HitSpellEffect hitEffect;
1026 hitEffect.damage = calculateEffect(i);
1027 hitEffect.effIndex = i;
1028 hitEffect.travelTime = Util::float2int32(travelTime);
1029
1030 m_hitEffects.insert(std::make_pair(guid, hitEffect));
1031 }
1032 }
1033 }
1034 else
1035 {
1036 // Spell was not reflected and it did not hit target
1037 MissSpellEffect missEffect;
1038 missEffect.missInfo = missedTarget;
1039 missEffect.travelTime = Util::float2int32(travelTime);
1040
1041 m_missEffects.insert(std::make_pair(missedTarget.targetGuid, missEffect));
1042 }
1043 }
1044}
void handleMissedEffect(SpellTargetMod const missedTarget, bool reCheckTarget=false)
Definition Spell.cpp:1046
Here is the call graph for this function:
Here is the caller graph for this function:

◆ HandleTargetNoObject()

void Spell::HandleTargetNoObject ( )

Definition at line 3057 of file Spell.Legacy.cpp.

3058{
3059 float dist = 3;
3060 float newx = m_caster->GetPositionX() + cosf(m_caster->GetOrientation()) * dist;
3061 float newy = m_caster->GetPositionY() + sinf(m_caster->GetOrientation()) * dist;
3062 float newz = m_caster->GetPositionZ();
3063
3064 //clamp Z
3065 newz = m_caster->getMapHeight(LocationVector(newx, newy, newz));
3066
3067 bool isInLOS = m_caster->IsWithinLOS(LocationVector(newx, newy, newz));
3068 //if not in line of sight, or too far away we summon inside caster
3069 if (fabs(newz - m_caster->GetPositionZ()) > 10 || !isInLOS)
3070 {
3071 newx = m_caster->GetPositionX();
3072 newy = m_caster->GetPositionY();
3073 newz = m_caster->GetPositionZ();
3074 }
3075
3077 m_targets.setDestination(LocationVector(newx, newy, newz));
3078}
const float & GetOrientation() const
Definition Object.hpp:357
void addTargetMask(uint32_t mask)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ HandleTeleport()

void Spell::HandleTeleport ( LocationVector  position,
uint32_t  mapid,
Unit Target 
)

Definition at line 2674 of file Spell.Legacy.cpp.

2675{
2676 if (Target->isPlayer())
2677 {
2678 Player* pTarget = static_cast<Player*>(Target);
2679 pTarget->eventAttackStop();
2680 pTarget->setTargetGuid(0);
2681
2682 // We use a teleport event on this one. Reason being because of UpdateCellActivity,
2683 // the game object set of the updater thread WILL Get messed up if we teleport from a gameobject
2684 // caster.
2685
2686 if (!sEventMgr.HasEvent(pTarget, EVENT_PLAYER_TELEPORT))
2687 {
2689 }
2690 }
2691 else
2692 {
2693 if (mapid != Target->GetMapId())
2694 {
2695 sLogger.failure("Tried to teleport a Creature to another map.");
2696 return;
2697 }
2698
2700
2701 data << Target->GetNewGUID();
2702 data << uint8_t(0);
2703 data << Target->GetPositionX();
2704 data << Target->GetPositionY();
2705 data << Target->GetPositionZ();
2706 data << Util::getMSTime();
2707 data << uint8_t(0x00);
2708 data << uint32_t(256);
2709 data << uint32_t(1);
2710 data << uint32_t(1);
2711 data << float(pos.x);
2712 data << float(pos.y);
2713 data << float(pos.z);
2714
2715 Target->sendMessageToSet(&data, true);
2716 Target->SetPosition(pos.x, pos.y, pos.z, pos.o);
2717 }
2718}
@ EVENT_PLAYER_TELEPORT
Definition EventMgr.h:59
@ SMSG_MONSTER_MOVE
Definition Opcodes.hpp:265
bool SetPosition(float newX, float newY, float newZ, float newOrientation, bool allowPorting=false)
Definition Object.cpp:3354
void eventTeleport(uint32_t mapId, LocationVector position, uint32_t instanceId=0)
Definition Player.cpp:1767
uint32_t getMSTime()
Definition Util.cpp:143
Here is the call graph for this function:
Here is the caller graph for this function:

◆ hasAttribute()

bool Spell::hasAttribute ( SpellAttributes  _attribute) const

Definition at line 5794 of file Spell.cpp.

5795{
5796 return (getSpellInfo()->getAttributes() & _attribute) != 0;
5797}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ hasAttributeEx()

bool Spell::hasAttributeEx ( SpellAttributesEx  _attribute) const

Definition at line 5799 of file Spell.cpp.

5800{
5801 return (getSpellInfo()->getAttributesEx() & _attribute) != 0;
5802}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ hasAttributeExB()

bool Spell::hasAttributeExB ( SpellAttributesExB  _attribute) const

Definition at line 5804 of file Spell.cpp.

5805{
5806 return (getSpellInfo()->getAttributesExB() & _attribute) != 0;
5807}
Here is the call graph for this function:

◆ hasAttributeExC()

bool Spell::hasAttributeExC ( SpellAttributesExC  _attribute) const

Definition at line 5809 of file Spell.cpp.

5810{
5811 return (getSpellInfo()->getAttributesExC() & _attribute) != 0;
5812}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ hasAttributeExD()

bool Spell::hasAttributeExD ( SpellAttributesExD  _attribute) const

Definition at line 5814 of file Spell.cpp.

5815{
5816 return (getSpellInfo()->getAttributesExD() & _attribute) != 0;
5817}
Here is the call graph for this function:

◆ hasAttributeExE()

bool Spell::hasAttributeExE ( SpellAttributesExE  _attribute) const

Definition at line 5819 of file Spell.cpp.

5820{
5821 return (getSpellInfo()->getAttributesExE() & _attribute) != 0;
5822}
Here is the call graph for this function:

◆ hasAttributeExF()

bool Spell::hasAttributeExF ( SpellAttributesExF  _attribute) const

Definition at line 5824 of file Spell.cpp.

5825{
5826 return (getSpellInfo()->getAttributesExF() & _attribute) != 0;
5827}
Here is the call graph for this function:

◆ hasAttributeExG()

bool Spell::hasAttributeExG ( SpellAttributesExG  _attribute) const

Definition at line 5829 of file Spell.cpp.

5830{
5831 return (getSpellInfo()->getAttributesExG() & _attribute) != 0;
5832}
Here is the call graph for this function:

◆ hasTarget()

bool Spell::hasTarget ( const uint64_t _guid,
std::vector< uint64_t > *  tmpGuidMap 
)

Definition at line 5666 of file Spell.cpp.

5667{
5668 for (const uint64_t& guid : *tmpGuidMap)
5669 if (guid == _guid)
5670 return true;
5671
5672 for (const auto target: m_missedTargets)
5673 if (target.targetGuid == _guid)
5674 return true;
5675
5676 return false;
5677}
#define true
Definition StormPort.h:32
unsigned __int64 uint64_t

◆ InitProtoOverride()

void Spell::InitProtoOverride ( )

Definition at line 1675 of file Spell.Legacy.cpp.

1676{
1677 if (m_spellInfo_override != nullptr)
1678 return;
1679 m_spellInfo_override = sSpellMgr.getSpellInfo(getSpellInfo()->getId());
1680}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ IsAspect()

bool Spell::IsAspect ( )

Definition at line 1630 of file Spell.Legacy.cpp.

1631{
1632 switch (getSpellInfo()->getId())
1633 {
1634 case 2596:
1635 case 5118:
1636 case 14320:
1637 case 13159:
1638 case 13161:
1639 case 20190:
1640 case 20043:
1641 case 14322:
1642 case 14321:
1643 case 13163:
1644 case 14319:
1645 case 14318:
1646 case 13165:
1647 return true;
1648 default:
1649 return false;
1650 }
1651}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ IsInvisibilitySpell()

bool Spell::IsInvisibilitySpell ( )

Definition at line 93 of file Spell.Legacy.cpp.

94{
95 //check if aura name is some invisibility aura
96 if (getSpellInfo()->getEffectApplyAuraName(0) == SPELL_AURA_MOD_INVISIBILITY || getSpellInfo()->getEffectApplyAuraName(1) == SPELL_AURA_MOD_INVISIBILITY || getSpellInfo()->getEffectApplyAuraName(2) == SPELL_AURA_MOD_INVISIBILITY)
97 return true;
98 return false;
99}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ IsSeal()

bool Spell::IsSeal ( )

Definition at line 1653 of file Spell.Legacy.cpp.

1654{
1655 switch (getSpellInfo()->getId())
1656 {
1657 case 13903:
1658 case 17177:
1659 case 20154:
1660 case 20164:
1661 case 20165:
1662 case 20166:
1663 case 20375:
1664 case 21084:
1665 case 31801:
1666 case 31892:
1667 case 53720:
1668 case 53736:
1669 return true;
1670 default:
1671 return false;
1672 }
1673}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ IsStealthSpell()

bool Spell::IsStealthSpell ( )

Definition at line 84 of file Spell.Legacy.cpp.

85{
86 //check if aura name is some stealth aura
87 if (getSpellInfo()->getEffectApplyAuraName(0) == SPELL_AURA_MOD_STEALTH || getSpellInfo()->getEffectApplyAuraName(1) == SPELL_AURA_MOD_STEALTH || getSpellInfo()->getEffectApplyAuraName(2) == SPELL_AURA_MOD_STEALTH)
88 return true;
89 return false;
90}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ prepare()

SpellCastResult Spell::prepare ( SpellCastTargets targets)

Definition at line 255 of file Spell.cpp.

256{
257 if (!m_caster->IsInWorld())
258 {
259 sLogger.debugFlag(AscEmu::Logging::LF_SPELL, "Object {} is casting spell ID {} while not in world", std::to_string(m_caster->getGuid()), getSpellInfo()->getId());
260 delete this;
262 }
263
264 if (p_caster != nullptr)
265 {
266 // Call Lua script hook
267 if (!sHookInterface.OnCastSpell(p_caster, getSpellInfo(), this))
268 {
271 }
272
273 //\ todo: convert this hack to spell script
275 {
276 sEventMgr.RemoveEvents(p_caster, EVENT_CANNIBALIZE);
278 p_caster->m_cannibalize = false;
279 }
280 }
281
282 // Check if spell is disabled
283 if (sSpellMgr.isSpellDisabled(getSpellInfo()->getId()))
284 {
286 finish(false);
288 }
289
290 // Check if caster is casting another spell
291 if (!m_triggeredSpell && m_caster->isCastingSpell(true, true))
292 {
294 finish(false);
296 }
297
299 m_targets = *targets;
300
301 // Set casting position
306
307 // Initialize spell cast time
308 m_castTime = 0;
309 if (!(m_triggeredByAura != nullptr || m_triggeredSpell && (getSpellInfo()->getManaCost() > 0 || getSpellInfo()->getManaCostPercentage() > 0)))
310 {
311 m_castTime = static_cast<int32_t>(GetCastTime(sSpellCastTimesStore.lookupEntry(getSpellInfo()->getCastingTimeIndex())));
312 if (m_castTime > 0 && u_caster != nullptr)
313 {
314 // Apply cast time modifiers
316
317 // Apply haste modifier to non-tradeskill spells
318 if (!(getSpellInfo()->getAttributes() & (ATTRIBUTES_ABILITY | ATTRIBUTES_TRADESPELL)))
319 {
321 }
322 // Apply ranged haste modifier to ranged spells with cast time
324 {
326 }
327
328 // Instant cast if target is in a non-traded trade slot
329 if (p_caster != nullptr && p_caster->getTradeData() != nullptr)
330 {
332 if (tradeItem != nullptr && tradeItem->getGuid() == m_targets.getItemTargetGuid())
333 m_castTime = 0;
334 }
335 }
336 }
337
338 // Check for cast time cheat
339 if (m_castTime < 0 || (p_caster != nullptr && p_caster->m_cheats.hasCastTimeCheat))
340 m_castTime = 0;
341
342 // Initialize power cost
343 // Spells casted from items should not use any power
344 m_powerCost = i_caster != nullptr ? 0 : calculatePowerCost();
345
346 // Item spells or triggered spells should not require combo points
347 if (m_triggeredSpell || i_caster != nullptr)
348 m_requiresCP = false;
349
351
352 // Check if spell can be casted
353 uint32_t parameter1 = 0, parameter2 = 0;
354 cancastresult = canCast(false, &parameter1, &parameter2);
356 {
357 // Triggered spells also need to go through cancast check but they do not pop a error message
359 // Also need to send SMSG_SPELL_FAILED_OTHER, otherwise spell button gets stuck
361
362 if (m_triggeredByAura != nullptr)
363 {
366 }
367
368 sLogger.debugFlag(AscEmu::Logging::LF_SPELL, "Spell::prepare : canCast result {} for spell id {} (refer to SpellFailure.hpp to work out why)", cancastresult, getSpellInfo()->getId());
369
370 finish(false);
371 return cancastresult;
372 }
373
375
377
378 if (!m_triggeredSpell || getSpellInfo()->isChanneled())
380
381 if (!m_triggeredSpell)
382 {
383 if (m_timer > 0)
384 {
385 // Remove stealth here only if spell has cast time
386 // Stealth is removed for instant spells in ::cast
387 if (p_caster != nullptr)
388 {
389 if (!(getSpellInfo()->getAttributesEx() & ATTRIBUTESEX_NOT_BREAK_STEALTH))
391
392 // Remove Feign Death auras
394 }
395
396 // Call for scripted at start casting hook
397 sScriptMgr.callScriptedSpellAtStartCasting(this);
398 }
399
400 // Send cast bar
402
403 // Send global cooldown
404 if (p_caster != nullptr && !p_caster->m_cheats.hasCastTimeCheat)
406
407 // Handle instant and non-channeled spells instantly. Other spells will be handled in ::update on next tick.
408 // First autorepeat casts are actually never casted, only set as current spell. Player::updateAutoRepeatSpell handles the shooting.
409 if (m_castTime == 0 && !getSpellInfo()->isChanneled() && !getSpellInfo()->isRangedAutoRepeat())
410 castMe(false);
411 else
413 }
414 else
415 {
416 castMe(false);
417 }
418
419 // TODO: for future reference, I removed aurastate removal here if spell had any aurastate set in SpellInfo::CasterAuraState
420 // this is not handled anywhere yet -Appled
421
422 return cancastresult;
423}
@ EVENT_CANNIBALIZE
Definition EventMgr.h:48
#define sHookInterface
@ ATTRIBUTES_TRADESPELL
@ SPELL_FAILED_UNKNOWN
@ SPELLMOD_CAST_TIME
@ SPELL_STATE_PREPARING
@ EMOTE_ONESHOT_NONE
uint32_t SERVER_DECL GetCastTime(WDB::Structures::SpellCastTimesEntry const *time)
Definition WDBStores.cpp:30
SERVER_DECL WDB::WDBContainer< WDB::Structures::SpellCastTimesEntry > sSpellCastTimesStore
void removeAura(AuraRemoveMode mode=AURA_REMOVE_BY_SERVER)
void setCurrentSpell(Spell *curSpell)
Definition Object.cpp:617
bool isCastingSpell(bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false) const
Definition Object.cpp:735
void addGarbageSpell(Spell *spell)
Definition Object.cpp:1495
void addGlobalCooldown(SpellInfo const *spellInfo, Spell *castingSpell, const bool sendPacket=false)
Definition Player.cpp:4378
bool m_cannibalize
Definition Player.hpp:2095
bool isRangedAutoRepeat() const
float_t m_castPositionY
Definition Spell.hpp:156
float_t m_castPositionO
Definition Spell.hpp:158
void _loadInitialTargetPointers(bool reset=false)
Definition Spell.cpp:6234
float_t m_castPositionZ
Definition Spell.hpp:157
void castMe(const bool doReCheck)
Definition Spell.cpp:425
float_t m_castPositionX
Definition Spell.hpp:155
void sendSpellStart()
Definition Spell.cpp:4627
TradeData * getTargetTradeData() const
Definition TradeData.cpp:31
void setEmoteState(uint32_t id)
Definition Unit.cpp:1446
float getAttackSpeedModifier(WeaponDamageType type) const
Definition Unit.cpp:6930
Here is the call graph for this function:

◆ removeCastItem()

void Spell::removeCastItem ( )
private

Definition at line 6013 of file Spell.cpp.

6014{
6015 if (getItemCaster() == nullptr)
6016 return;
6017
6018 auto removable = false, chargesUsed = false;
6019 const auto proto = getItemCaster()->getItemProperties();
6020
6021 for (uint8_t i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
6022 {
6023 const auto protoSpell = proto->Spells[i];
6024 if (protoSpell.Id > 0)
6025 {
6026 if (protoSpell.Charges == 0)
6027 continue;
6028
6029 // Items with negative charges disappear when they reach 0 charges
6030 if (protoSpell.Charges < 0)
6031 removable = true;
6032
6033 auto charges = getItemCaster()->getSpellCharges(i);
6034 if (charges != 0 && protoSpell.Id == getSpellInfo()->getId())
6035 {
6036 if (charges > 0)
6037 --charges;
6038 else
6039 ++charges;
6040
6041 // If item is not stackable, modify charges
6042 if (proto->MaxCount == 1)
6043 getItemCaster()->setSpellCharges(i, charges);
6044
6045 getItemCaster()->m_isDirty = true;
6046 }
6047
6048 chargesUsed = charges == 0;
6049 }
6050 }
6051
6052 if (removable && chargesUsed)
6053 {
6054 // If the item is stacked, remove 1 from the stack
6055 if (getItemCaster()->getStackCount() > 1)
6056 {
6058 getItemCaster()->m_isDirty = true;
6059 }
6060 else
6061 {
6063 }
6064
6065 i_caster = nullptr;
6066 }
6067}
bool SafeFullRemoveItemByGuid(uint64_t guid)
Removes the item safely by guid, supports full inventory.
void modStackCount(int32_t mod)
Definition Item.cpp:145
bool m_isDirty
Definition Item.hpp:258
void setSpellCharges(uint8_t index, int32_t count)
Definition Item.cpp:167
Here is the call graph for this function:
Here is the caller graph for this function:

◆ removeReagents()

void Spell::removeReagents ( )
private

Definition at line 6069 of file Spell.cpp.

6070{
6071 if (p_caster == nullptr)
6072 return;
6073
6074#if VERSION_STRING >= TBC
6075 if (!(p_caster->hasUnitFlags(UNIT_FLAG_NO_REAGANT_COST) && getSpellInfo()->getAttributesExE() & ATTRIBUTESEXE_REAGENT_REMOVAL))
6076#endif
6077 {
6078 for (uint8_t i = 0; i < MAX_SPELL_REAGENTS; ++i)
6079 {
6080 if (getSpellInfo()->getReagent(i) == 0)
6081 continue;
6082
6083 const auto itemId = static_cast<uint32_t>(getSpellInfo()->getReagent(i));
6085 }
6086 }
6087}
uint32_t RemoveItemAmt_ProtectPointer(uint32_t id, uint32_t amt, Item **pointer)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ removeUsedSpellModifier()

void Spell::removeUsedSpellModifier ( AuraEffectModifier const aurEff)

Definition at line 5862 of file Spell.cpp.

5863{
5864 for (auto& usedMod : m_usedModifiers)
5865 {
5866 // Mark the spell modifier as removed to prevent memory corruption
5867 if (usedMod.first == aurEff)
5868 {
5869 usedMod.second = true;
5870 break;
5871 }
5872 }
5873
5874 // Also, remove the spell modifier from pending auras
5875 for (auto& pendingAur : m_pendingAuras)
5876 {
5877 if (pendingAur.second.aur != nullptr)
5878 pendingAur.second.aur->removeUsedSpellModifier(aurEff);
5879 }
5880}
Here is the call graph for this function:

◆ resetSpellInfoOverride()

void Spell::resetSpellInfoOverride ( )

Definition at line 5834 of file Spell.cpp.

5835{
5836 m_spellInfo_override = nullptr;
5837}
Here is the caller graph for this function:

◆ safeAddMissedTarget()

void Spell::safeAddMissedTarget ( uint64_t  targetGuid,
SpellDidHitResult  hitResult,
SpellDidHitResult  extendedHitResult 
)
private

Definition at line 5775 of file Spell.cpp.

5776{
5777 for (const auto& targetMod : m_missedTargets)
5778 {
5779 // Check if target is already in the vector
5780 if (targetMod.targetGuid == targetGuid)
5781 return;
5782 }
5783
5784 m_missedTargets.push_back(SpellTargetMod(targetGuid, hitResult, extendedHitResult));
5785}
Here is the caller graph for this function:

◆ SafeAddTarget()

void Spell::SafeAddTarget ( std::vector< uint64_t > *  tgt,
uint64_t  guid 
)

Definition at line 2885 of file Spell.Legacy.cpp.

2886{
2887 if (guid == 0)
2888 return;
2889
2890 for (std::vector<uint64_t>::iterator i = tgt->begin(); i != tgt->end(); ++i)
2891 {
2892 if (*i == guid)
2893 {
2894 return;
2895 }
2896 }
2897
2898 tgt->push_back(guid);
2899}
Here is the caller graph for this function:

◆ sendCastResult() [1/2]

void Spell::sendCastResult ( Player caster,
uint8_t  castCount,
SpellCastResult  result,
uint32_t  parameter1,
uint32_t  parameter2 
)
private

Definition at line 5310 of file Spell.cpp.

5311{
5312 if (caster == nullptr)
5313 return;
5314
5315 // Include missing parameters to error messages
5316 switch (result)
5317 {
5319 if (parameter1 == 0)
5320 parameter1 = getSpellInfo()->getRequiredShapeShift();
5321 break;
5323 if (parameter1 == 0)
5324 {
5325#if VERSION_STRING == TBC
5326 parameter1 = getSpellInfo()->getRequiresAreaId();
5327#elif VERSION_STRING >= WotLK
5328 // Send the first area id from areagroup to player
5329 auto areaGroup = sAreaGroupStore.lookupEntry(static_cast<uint32_t>(getSpellInfo()->getRequiresAreaId()));
5330 for (const auto& areaId : areaGroup->AreaId)
5331 {
5332 if (areaId != 0)
5333 {
5334 parameter1 = areaId;
5335 break;
5336 }
5337 }
5338#endif
5339 } break;
5343 if (parameter1 == 0 && parameter2 == 0)
5344 {
5345 parameter1 = static_cast<uint32_t>(getSpellInfo()->getEquippedItemClass());
5346 parameter2 = static_cast<uint32_t>(getSpellInfo()->getEquippedItemSubClass());
5347 } break;
5348#if VERSION_STRING >= TBC
5349 case SPELL_FAILED_REAGENTS:
5350 if (parameter1 == 0)
5351 {
5352 for (uint8_t i = 0; i < MAX_SPELL_REAGENTS; ++i)
5353 {
5354 if (getSpellInfo()->getReagent(i) == 0)
5355 continue;
5356
5357 const auto itemId = static_cast<uint32_t>(getSpellInfo()->getReagent(i));
5358 if (!caster->hasItem(itemId, getSpellInfo()->getReagentCount(i)))
5359 {
5360 parameter1 = itemId;
5361 break;
5362 }
5363 }
5364 } break;
5365 case SPELL_FAILED_TOTEMS:
5366 if (parameter1 == 0)
5367 {
5368 for (uint8_t i = 0; i < MAX_SPELL_TOTEMS; ++i)
5369 {
5370 if (getSpellInfo()->getTotem(i) == 0)
5371 continue;
5372 if (!caster->hasItem(getSpellInfo()->getTotem(i)))
5373 {
5374 parameter1 = getSpellInfo()->getTotem(i);
5375 break;
5376 }
5377 }
5378 } break;
5379 case SPELL_FAILED_TOTEM_CATEGORY:
5380 if (parameter1 == 0)
5381 {
5382 for (uint8_t i = 0; i < MAX_SPELL_TOTEM_CATEGORIES; ++i)
5383 {
5384 if (getSpellInfo()->getTotemCategory(i) == 0)
5385 continue;
5386 if (!caster->getItemInterface()->hasItemForTotemCategory(getSpellInfo()->getTotemCategory(i)))
5387 {
5388 parameter1 = getSpellInfo()->getTotemCategory(i);
5389 break;
5390 }
5391 }
5392 } break;
5393#endif
5395 if (parameter1 == 0)
5396 parameter1 = getSpellInfo()->getRequiresSpellFocus();
5397 break;
5398 default:
5399 break;
5400 }
5401
5402 caster->sendCastFailedPacket(getSpellInfo()->getId(), result, castCount, parameter1, parameter2);
5403}
void sendCastFailedPacket(uint32_t spellId, uint8_t errorMessage, uint8_t multiCast, uint32_t extra1, uint32_t extra2=0)
Definition Player.cpp:9714
uint32_t getRequiredShapeShift() const
Here is the call graph for this function:

◆ sendCastResult() [2/2]

void Spell::sendCastResult ( SpellCastResult  result,
uint32_t  parameter1 = 0,
uint32_t  parameter2 = 0 
)

Definition at line 4552 of file Spell.cpp.

4553{
4554 if (result == SPELL_CAST_SUCCESS)
4555 return;
4556
4558
4559 if (!m_caster->IsInWorld())
4560 return;
4561
4562 Player* plr = p_caster;
4563 if (plr == nullptr && u_caster != nullptr)
4564 {
4566
4567 if (plr == nullptr && getUnitCaster()->isVehicle())
4568 plr = getUnitCaster()->getPlayerOwner();
4569 }
4570
4571 if (plr == nullptr)
4572 return;
4573
4574 sendCastResult(plr, 0, result, parameter1, parameter2);
4575}
virtual Player * getPlayerOwner()
Definition Object.cpp:1751
void SetSpellFailed(bool failed=true)
Player * m_redirectSpellPackets
Definition Unit.hpp:1502
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sendChannelStart()

void Spell::sendChannelStart ( const uint32_t  duration)
private

Definition at line 5273 of file Spell.cpp.

5274{
5275 m_caster->sendMessageToSet(MsgChannelStart(m_caster->GetNewGUID(), getSpellInfo()->getId(), duration).serialise().get(), true);
5276
5277 Object const* channelTarget = nullptr;
5278 if (!m_uniqueHittedTargets.empty())
5279 {
5280 // Select first target from uniqueHittedTargets
5281 // brief: the channel target is properly set in SpellEffects.cpp for persistent dynamic objects
5282 for (const auto& targetGuid : m_uniqueHittedTargets)
5283 {
5284 const auto targetUnit = m_caster->getWorldMapUnit(targetGuid.first);
5285 if (targetUnit != nullptr)
5286 {
5287 channelTarget = targetUnit;
5288 break;
5289 }
5290
5291 const auto objTarget = m_caster->getWorldMapGameObject(targetGuid.first);
5292 if (objTarget != nullptr)
5293 {
5294 channelTarget = objTarget;
5295 break;
5296 }
5297 }
5298 }
5299
5300 if (u_caster != nullptr)
5301 {
5303 if (channelTarget != nullptr)
5304 u_caster->setChannelObjectGuid(channelTarget->getGuid());
5305 }
5306
5307 m_timer = duration;
5308}
void setChannelSpellId(uint32_t spell_id)
Definition Unit.cpp:407
void setChannelObjectGuid(uint64_t guid)
Definition Unit.cpp:404
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sendChannelUpdate()

void Spell::sendChannelUpdate ( const uint32_t  time,
const uint32_t  diff = 0 
)

Definition at line 4577 of file Spell.cpp.

4578{
4579 if (time == 0)
4580 {
4581 if (u_caster != nullptr)
4582 {
4583 const auto channelGuid = u_caster->getChannelObjectGuid();
4584
4585 // Make sure last periodic tick happens
4586 if (diff > 0)
4587 {
4588 const auto casterGuid = u_caster->getGuid();
4589 const auto aur = u_caster->getAuraWithIdForGuid(getSpellInfo()->getId(), casterGuid);
4590 const auto target = u_caster->getWorldMapUnit(channelGuid);
4591
4592 if (aur != nullptr)
4593 aur->update(diff, true);
4594
4595 if (target != nullptr)
4596 {
4597 const auto targetAur = target->getAuraWithIdForGuid(getSpellInfo()->getId(), casterGuid);
4598 if (targetAur != nullptr)
4599 targetAur->update(diff, true);
4600 }
4601 }
4602
4603 const auto dynamicObject = u_caster->getWorldMapDynamicObject(WoWGuid::getGuidLowPartFromUInt64(channelGuid));
4604 if (dynamicObject != nullptr)
4605 dynamicObject->remove();
4606
4609
4610 // Remove temporary summons which were created by this channeled spell (i.e Eye of Kilrogg)
4611 if (p_caster != nullptr && p_caster->getCharmGuid() != 0 && getSpellInfo()->hasEffect(SPELL_EFFECT_SUMMON))
4612 {
4613 const auto charmedUnit = p_caster->getWorldMapUnit(p_caster->getCharmGuid());
4614 if (charmedUnit != nullptr && charmedUnit->getCreatedBySpellId() == getSpellInfo()->getId())
4616 }
4617
4618 // Channel ended, remove the aura
4619 //\ todo: if aura is stackable, need to remove only one stack from aura instead of whole aura!
4621 }
4622 }
4623
4625}
void update(unsigned long diff, bool skipDurationCheck=false)
Aura * getAuraWithIdForGuid(uint32_t const *auraId, uint64_t guid) const
Definition Unit.cpp:4877
void unPossess()
Definition Unit.cpp:9007
static uint32_t getGuidLowPartFromUInt64(uint64_t guid)
Definition WoWGuid.h:228
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SendInterrupted()

void Spell::SendInterrupted ( uint8_t  result)

Definition at line 1191 of file Spell.Legacy.cpp.

1192{
1194
1195 if (m_caster == nullptr || !m_caster->IsInWorld())
1196 return;
1197
1198 // send the failure to pet owner if we're a pet
1199 Player* plr = p_caster;
1200 if (plr == nullptr && m_caster->isPet())
1201 {
1202 static_cast<Pet*>(m_caster)->sendPetCastFailed(getSpellInfo()->getId(), result);
1203 }
1204 else
1205 {
1206 if (plr == nullptr && u_caster != nullptr && u_caster->m_redirectSpellPackets != nullptr)
1208
1209 if (plr != nullptr && plr->isPlayer())
1211 }
1212
1214}
void SendPacket(WorldPacket *packet)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SendLogExecute()

void Spell::SendLogExecute ( uint32_t  damage,
uint64_t targetGuid 
)

Definition at line 1176 of file Spell.Legacy.cpp.

1177{
1179 data << m_caster->GetNewGUID();
1180 data << getSpellInfo()->getId();
1181 data << uint32_t(1);
1182 data << getSpellInfo()->getSpellVisual(0);
1183 data << uint32_t(1);
1184 if (m_caster->getGuid() != targetGuid)
1185 data << targetGuid;
1186 if (spellDamage)
1187 data << spellDamage;
1188 m_caster->sendMessageToSet(&data, true);
1189}
@ SMSG_SPELLLOGEXECUTE
Definition Opcodes.hpp:648
uint32_t getSpellVisual(uint8_t visualIndex) const
Here is the call graph for this function:

◆ SendResurrectRequest()

void Spell::SendResurrectRequest ( Player target)

Definition at line 1216 of file Spell.Legacy.cpp.

1217{
1218 bool resurrectionSickness = false;
1219 std::string casterName;
1220 if (!m_caster->isPlayer() && m_caster->isCreature())
1221 {
1222 casterName = dynamic_cast<Creature*>(m_caster)->GetCreatureProperties()->Name;
1223
1224 if (dynamic_cast<Creature*>(m_caster)->isSpiritHealer())
1225 resurrectionSickness = true;
1226 }
1227
1228 bool overrideTimer = false;
1230 overrideTimer = true;
1231
1232 target->getSession()->SendPacket(SmsgResurrectRequest(m_caster->getGuid(), casterName, resurrectionSickness, overrideTimer, getSpellInfo()->getId()).serialise().get());
1234}
@ ATTRIBUTESEXC_IGNORE_RESURRECTION_TIMER
bool isSpiritHealer() const
Definition Creature.cpp:265
void setResurrecterGuid(uint64_t guid)
Definition Player.cpp:7774
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sendSpellGo()

void Spell::sendSpellGo ( )
private

Definition at line 4942 of file Spell.cpp.

4943{
4944#if VERSION_STRING == Mop
4945 if (!m_caster || !m_caster->IsInWorld())
4946 return;
4947
4948 // If spell has no visuals, it's not channeled and it's triggered, no need to send packet
4949 if (!(getSpellInfo()->isChanneled() || getSpellInfo()->getSpeed() > 0.0f || getSpellInfo()->getSpellVisual(0) != 0 ||
4950 getSpellInfo()->getSpellVisual(1) != 0 || (!m_triggeredSpell && m_triggeredByAura == nullptr)))
4951 return;
4952
4953 ObjectGuid casterGuid = i_caster ? i_caster->getGuid() : m_caster->getGuid();
4954 ObjectGuid casterUnitGuid = m_caster->getGuid();
4956 ObjectGuid itemTargetGuid = m_targets.getItemTargetGuid();
4957 ObjectGuid unkGuid = 0;
4960 bool hasDestUnkByte = m_targets.getTargetMask() & TARGET_FLAG_DEST_LOCATION;
4961 bool hasTargetString = m_targets.getTargetMask() & TARGET_FLAG_STRING;
4962 bool hasPredictedHeal = false;
4963 bool hasPredictedType = false;
4964 bool hasTargetMask = m_targets.getTargetMask() != 0;
4965 bool hasCastImmunities = false;
4966 bool hasCastSchoolImmunities = false;
4967 bool hasElevation = false;
4968 bool hasDelayTime = false;
4969 bool hasVisualChain = false;
4970 bool hasAmmoInventoryType = false;
4971 bool hasAmmoDisplayId = false;
4972 bool hasRunesStateBefore = false;
4973 bool hasRunesStateAfter = false;
4974 uint8_t predictedPowerCount = false;
4975 uint8_t runeCooldownPassedCount = false;
4976
4977 WorldPacket data(SMSG_SPELL_GO, 60);
4978
4979 data.writeBit(casterUnitGuid[2]);
4980 data.writeBit(1); // hasAmmoDisplayType
4981 data.writeBit(hasSourceLocation);
4982 data.writeBit(casterGuid[2]);
4983
4984
4985 data.writeBit(casterGuid[6]);
4986 data.writeBit(!hasDestUnkByte);
4987 data.writeBit(casterUnitGuid[7]);
4988 data.writeBits(0, 20); // Extra Target Count
4989
4990 size_t missTypeCountPos = data.bitwpos();
4991 data.writeBits(0, 25); // Miss Type Count
4992
4993 size_t missCountPos = data.bitwpos();
4994 data.writeBits(0, 24); // Miss Count
4995
4996 data.writeBit(casterUnitGuid[1]);
4997 data.writeBit(casterGuid[0]);
4998 data.writeBits(0, 13); // Unknown bits
4999
5000
5001 data.writeBit(casterUnitGuid[5]);
5002 data.writeBit(0); // Fake bit
5003 data.writeBit(0); // Fake bit
5004 data.writeBit(!hasTargetString);
5005
5006 data.writeBit(itemTargetGuid[7]);
5007 data.writeBit(itemTargetGuid[2]);
5008 data.writeBit(itemTargetGuid[1]);
5009 data.writeBit(itemTargetGuid[3]);
5010 data.writeBit(itemTargetGuid[6]);
5011 data.writeBit(itemTargetGuid[0]);
5012 data.writeBit(itemTargetGuid[5]);
5013 data.writeBit(itemTargetGuid[4]);
5014
5015 data.writeBit(casterGuid[7]);
5016
5017 data.writeBit(targetGuid[0]);
5018 data.writeBit(targetGuid[6]);
5019 data.writeBit(targetGuid[5]);
5020 data.writeBit(targetGuid[7]);
5021 data.writeBit(targetGuid[4]);
5022 data.writeBit(targetGuid[2]);
5023 data.writeBit(targetGuid[3]);
5024 data.writeBit(targetGuid[1]);
5025
5026 data.writeBit(!hasRunesStateBefore);
5027 data.writeBits(predictedPowerCount, 21); // predictedPowerCount
5028 data.writeBit(casterGuid[1]);
5029 data.writeBit(!hasPredictedType);
5030 data.writeBit(!hasTargetMask);
5031 data.writeBit(casterUnitGuid[3]);
5032
5033 data.writeBit(1); // Missing Predict heal
5034 data.writeBit(0); // hasPowerData
5035 data.writeBit(1); // has castImmunitiy
5036 data.writeBit(casterUnitGuid[6]);
5037 data.writeBit(0); // Fake bit
5038 data.writeBit(hasVisualChain);
5039
5040 data.writeBit(unkGuid[7]);
5041 data.writeBit(unkGuid[6]);
5042 data.writeBit(unkGuid[1]);
5043 data.writeBit(unkGuid[2]);
5044 data.writeBit(unkGuid[0]);
5045 data.writeBit(unkGuid[5]);
5046 data.writeBit(unkGuid[3]);
5047 data.writeBit(unkGuid[4]);
5048
5049 data.writeBit(!hasDelayTime);
5050 data.writeBit(1); // has School Immunities
5051 data.writeBits(runeCooldownPassedCount, 3); // runeCooldownPassedCount
5052 data.writeBit(casterUnitGuid[0]);
5053
5054 if (hasTargetMask)
5055 data.writeBits(m_targets.getTargetMask(), 20);
5056
5057 data.writeBit(!hasElevation);
5058 data.writeBit(!hasRunesStateAfter);
5059 data.writeBit(casterGuid[4]);
5060 data.writeBit(1); // hasAmmodisplayID
5061 data.writeBit(hasDestLocation);
5062 data.writeBit(casterGuid[5]);
5063
5064 data.writeBits(0, 24); // Hit Count
5065
5066 data.writeBit(casterUnitGuid[4]);
5067
5068 data.writeBit(casterGuid[3]);
5069 data.flushBits();
5070
5071 data.WriteByteSeq(targetGuid[5]);
5072 data.WriteByteSeq(targetGuid[2]);
5073 data.WriteByteSeq(targetGuid[1]);
5074 data.WriteByteSeq(targetGuid[6]);
5075 data.WriteByteSeq(targetGuid[0]);
5076 data.WriteByteSeq(targetGuid[3]);
5077 data.WriteByteSeq(targetGuid[4]);
5078 data.WriteByteSeq(targetGuid[7]);
5079
5080 data.WriteByteSeq(itemTargetGuid[5]);
5081 data.WriteByteSeq(itemTargetGuid[2]);
5082 data.WriteByteSeq(itemTargetGuid[0]);
5083 data.WriteByteSeq(itemTargetGuid[6]);
5084 data.WriteByteSeq(itemTargetGuid[7]);
5085 data.WriteByteSeq(itemTargetGuid[3]);
5086 data.WriteByteSeq(itemTargetGuid[1]);
5087 data.WriteByteSeq(itemTargetGuid[4]);
5088
5089 data.WriteByteSeq(casterGuid[2]);
5090
5091 data.WriteByteSeq(unkGuid[6]);
5092 data.WriteByteSeq(unkGuid[2]);
5093 data.WriteByteSeq(unkGuid[7]);
5094 data.WriteByteSeq(unkGuid[1]);
5095 data.WriteByteSeq(unkGuid[4]);
5096 data.WriteByteSeq(unkGuid[3]);
5097 data.WriteByteSeq(unkGuid[5]);
5098 data.WriteByteSeq(unkGuid[0]);
5099
5100
5101 data << uint32_t(Util::getMSTime());
5102
5103 data.WriteByteSeq(casterGuid[6]);
5104 data.WriteByteSeq(casterUnitGuid[7]);
5105 data.WriteByteSeq(casterGuid[1]);
5106
5107 if (hasVisualChain)
5108 {
5109 data << uint32_t(0);
5110 data << uint32_t(0);
5111 }
5112
5113 data << uint32_t(0);
5114
5115 data.WriteByteSeq(casterUnitGuid[6]);
5116
5117 if (hasPredictedType)
5118 data << uint8_t(0);
5119
5120 data.WriteByteSeq(casterGuid[4]);
5121 data.WriteByteSeq(casterUnitGuid[1]);
5122
5123 data.WriteByteSeq(casterGuid[0]);
5124
5125 data << uint8_t(0);
5126
5127 data.WriteByteSeq(casterGuid[5]);
5128 data.WriteByteSeq(casterUnitGuid[2]);
5129 data.WriteByteSeq(casterGuid[3]);
5130 data.WriteByteSeq(casterUnitGuid[5]);
5131
5132 data << uint32_t(m_spellInfo->getId());
5133
5134 data.WriteByteSeq(casterUnitGuid[0]);
5135 data.WriteByteSeq(casterUnitGuid[3]);
5136 data.WriteByteSeq(casterUnitGuid[4]);
5137 data.WriteByteSeq(casterGuid[7]);
5138
5139 m_caster->sendMessageToSet(&data, true);
5140#else
5141 if (!m_caster->IsInWorld())
5142 return;
5143
5144 // If spell has no visuals and it's not channeled and it's triggered, no need to send packet
5145 if (!(getSpellInfo()->isChanneled() || getSpellInfo()->getSpeed() > 0.0f || getSpellInfo()->getSpellVisual(0) != 0 ||
5146 getSpellInfo()->getSpellVisual(1) != 0 || (!m_triggeredSpell && m_triggeredByAura == nullptr)))
5147 return;
5148
5149 // Size should be enough
5150 WorldPacket data(SMSG_SPELL_GO, 60);
5151
5152 // Set cast flags
5153 uint32_t castFlags = 0;
5155 castFlags |= SPELL_PACKET_FLAGS_RANGED;
5156
5157 if (i_caster != nullptr)
5158 castFlags |= SPELL_PACKET_FLAGS_ITEM_CASTER;
5159
5160 if (!m_missedTargets.empty())
5162
5163#if VERSION_STRING >= WotLK
5164 if (m_missileTravelTime != 0)
5166
5167 // Rune update
5168 uint8_t currentRunes = 0;
5169 if (p_caster != nullptr && p_caster->isClassDeathKnight())
5170 {
5171 // Get current available runes in bitmask
5172 currentRunes = static_cast<DeathKnight*>(p_caster)->GetRuneFlags();
5173
5174 if (getSpellInfo()->getRuneCostID() > 0 || currentRunes != m_rune_avail_before)
5176 }
5177
5178 // Power update for players and their summons
5179 if ((p_caster != nullptr || (u_caster != nullptr && u_caster->getPlayerOwner() != nullptr)) &&
5182#endif
5183
5184 if (i_caster != nullptr)
5185 data << i_caster->GetNewGUID();
5186 else
5187 data << m_caster->GetNewGUID();
5188
5189 data << m_caster->GetNewGUID();
5190
5191#if VERSION_STRING >= WotLK
5192 data << uint8_t(extra_cast_number);
5193 data << uint32_t(getSpellInfo()->getId());
5194 data << uint32_t(castFlags);
5195#else
5196 data << uint32_t(getSpellInfo()->getId());
5197 data << uint16_t(castFlags);
5198#endif
5199#if VERSION_STRING >= Cata
5200 data << uint32_t(m_timer);
5201#endif
5202#if VERSION_STRING != Classic
5203 data << uint32_t(Util::getMSTime());
5204#endif
5205
5206 // Add hitted targets
5207 data << uint8_t(m_uniqueHittedTargets.size());
5208 for (const auto& uniqueTarget : m_uniqueHittedTargets)
5209 {
5210 data << uint64_t(uniqueTarget.first);
5211 }
5212
5213#if VERSION_STRING >= WotLK
5214 // Add missed targets
5215 if (castFlags & SPELL_PACKET_FLAGS_EXTRA_MESSAGE)
5216 {
5217 data << uint8_t(m_missedTargets.size());
5219 }
5220 else
5221 {
5222 data << uint8_t(0);
5223 }
5224
5225 m_targets.write(data);
5226
5227
5228 if (castFlags & SPELL_PACKET_FLAGS_POWER_UPDATE && u_caster != nullptr)
5229 data << uint32_t(u_caster->getPower(getSpellInfo()->getPowerType()));
5230#else
5231 data << uint8_t(m_missedTargets.size());
5232
5233 if (castFlags & SPELL_PACKET_FLAGS_EXTRA_MESSAGE)
5235
5236 m_targets.write(data);
5237#endif
5238
5239 if (castFlags & SPELL_PACKET_FLAGS_RANGED)
5241
5242#if VERSION_STRING >= WotLK
5243 //data order depending on flags : 0x800, 0x200000, 0x20000, 0x20, 0x80000, 0x40 (this is not spellgoflag but seems to be from spellentry or packet..)
5244 //.text:00401110 mov eax, [ecx+14h] -> them
5245 //.text:00401115 cmp eax, [ecx+10h] -> us
5246 if (castFlags & SPELL_PACKET_FLAGS_RUNE_UPDATE)
5247 {
5249 data << uint8_t(currentRunes);
5250 for (uint8_t i = 0; i < MAX_RUNES; ++i)
5251 {
5252 const uint8_t runeMask = 1U << i;
5253 if ((runeMask & m_rune_avail_before) != (runeMask & currentRunes))
5254 data << uint8_t(0); // Value of the rune converted into byte. We just think it is 0 but maybe it is not
5255 }
5256 }
5257
5258 if (castFlags & SPELL_PACKET_FLAGS_UPDATE_MISSILE)
5259 {
5260 data << float(m_missilePitch);
5262 }
5263
5264 // Some spells require this
5266 data << uint8_t(0);
5267#endif
5268
5269 m_caster->sendMessageToSet(&data, true);
5270#endif
5271}
@ SMSG_SPELL_GO
Definition Opcodes.hpp:350
#define MAX_RUNES
@ TARGET_FLAG_STRING
@ SPELL_PACKET_FLAGS_UNK40000
@ SPELL_PACKET_FLAGS_UPDATE_MISSILE
@ SPELL_PACKET_FLAGS_ITEM_CASTER
@ SPELL_PACKET_FLAGS_POWER_UPDATE
@ SPELL_PACKET_FLAGS_EXTRA_MESSAGE
@ SPELL_PACKET_FLAGS_RANGED
@ SPELL_PACKET_FLAGS_RUNE_UPDATE
void write(WorldPacket &data) const
PowerType getPowerType() const
uint32_t getRuneCostID() const
void writeSpellMissedTargets(WorldPacket *data)
Definition Spell.cpp:5515
void writeProjectileDataToPacket(WorldPacket *data)
Definition Spell.cpp:5405
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sendSpellStart()

void Spell::sendSpellStart ( )
private

Definition at line 4627 of file Spell.cpp.

4628{
4629#if VERSION_STRING == Mop
4630 if (!m_caster || !m_caster->IsInWorld())
4631 return;
4632
4633 // If spell has no visuals, it's not channeled and it's triggered, no need to send packet
4634 if (!(getSpellInfo()->isChanneled() || getSpellInfo()->getSpeed() > 0.0f || getSpellInfo()->getSpellVisual(0) != 0 ||
4635 getSpellInfo()->getSpellVisual(1) != 0 || (!m_triggeredSpell && m_triggeredByAura == nullptr)))
4636 return;
4637
4638 ObjectGuid casterGuid = i_caster ? i_caster ->getGuid() : m_caster->getGuid();
4639 ObjectGuid casterUnitGuid = m_caster->getGuid();
4641 ObjectGuid itemTargetGuid = m_targets.getItemTargetGuid();
4642 ObjectGuid unkGuid = 0;
4645 bool hasTargetString = false;// m_targets.getTargetMask()& TARGET_FLAG_STRING;
4646 bool hasPredictedHeal = false;
4647 bool hasPredictedType = false;
4648 bool hasTargetMask = m_targets.getTargetMask() != 0;
4649 bool hasCastImmunities = false;
4650 bool hasCastSchoolImmunities = false;
4651 bool hasElevation = false;
4652 bool hasVisualChain = false;
4653 bool hasAmmoInventoryType = false;
4654 bool hasAmmoDisplayId = false;
4655 uint8_t runeCooldownPassedCount = 0;
4656 uint8_t predictedPowerCount = 0;
4657
4658 WorldPacket data(SMSG_SPELL_START, 25);
4659
4660 data.writeBits(0, 24); // Miss Count (not used currently in SMSG_SPELL_START)
4661 data.writeBit(casterGuid[5]);
4662
4663 //for (uint32_t i = 0; i < missCount; ++i)
4664 //{
4665 //}
4666
4667 data.writeBit(1); // Unk read int8_t
4668 data.writeBit(0); // Fake Bit
4669 data.writeBit(casterUnitGuid[4]);
4670 data.writeBit(casterGuid[2]);
4671 data.writeBits(runeCooldownPassedCount, 3); // Rune Cooldown Passed Count
4672 data.writeBit(casterUnitGuid[2]);
4673 data.writeBit(casterUnitGuid[6]);
4674 data.writeBits(0, 25); // MissType Count (not used currently in SMSG_SPELL_START)
4675 data.writeBits(0, 13); // Unknown Bits
4676 data.writeBit(casterGuid[4]);
4677 data.writeBits(0, 24); // Hit Count (not used currently in SMSG_SPELL_START)
4678 data.writeBit(casterUnitGuid[7]);
4679
4680 //for (uint32_t i = 0; i < hitCount; ++i)
4681 //{
4682 //}
4683
4684 data.writeBit(hasSourceLocation);
4685 data.writeBits(predictedPowerCount, 21);
4686
4687 data.writeBit(itemTargetGuid[3]);
4688 data.writeBit(itemTargetGuid[0]);
4689 data.writeBit(itemTargetGuid[1]);
4690 data.writeBit(itemTargetGuid[7]);
4691 data.writeBit(itemTargetGuid[2]);
4692 data.writeBit(itemTargetGuid[6]);
4693 data.writeBit(itemTargetGuid[4]);
4694 data.writeBit(itemTargetGuid[5]);
4695
4696 data.writeBit(!hasElevation);
4697 data.writeBit(!hasTargetString);
4698 data.writeBit(!hasAmmoInventoryType);
4699 data.writeBit(hasDestLocation);
4700 data.writeBit(1); // Unk Read32
4701 data.writeBit(casterGuid[3]);
4702
4703 if (hasDestLocation)
4704 {
4705
4706 }
4707
4708 data.writeBit(!hasAmmoDisplayId);
4709
4710 if (hasSourceLocation)
4711 {
4712
4713 }
4714
4715 data.writeBit(0); // Fake Bit
4716 data.writeBit(casterGuid[6]);
4717
4718 data.writeBit(unkGuid[2]);
4719 data.writeBit(unkGuid[1]);
4720 data.writeBit(unkGuid[7]);
4721 data.writeBit(unkGuid[6]);
4722 data.writeBit(unkGuid[0]);
4723 data.writeBit(unkGuid[5]);
4724 data.writeBit(unkGuid[3]);
4725 data.writeBit(unkGuid[4]);
4726
4727 data.writeBit(!hasTargetMask);
4728
4729 if (hasTargetMask)
4730 data.writeBits(m_targets.getTargetMask(), 20);
4731
4732 data.writeBit(casterGuid[1]);
4733 data.writeBit(!hasPredictedHeal);
4734 data.writeBit(1); // Unk read int8_t
4735 data.writeBit(!hasCastSchoolImmunities);
4736 data.writeBit(casterUnitGuid[5]);
4737 data.writeBit(0); // Fake Bit
4738 data.writeBits(0, 20); // Extra Target Count (not used currently in SMSG_SPELL_START)
4739
4740 //for (uint32_t i = 0; i < extraTargetCount; ++i)
4741 //{
4742 //}
4743
4744 data.writeBit(targetGuid[1]);
4745 data.writeBit(targetGuid[4]);
4746 data.writeBit(targetGuid[6]);
4747 data.writeBit(targetGuid[7]);
4748 data.writeBit(targetGuid[5]);
4749 data.writeBit(targetGuid[3]);
4750 data.writeBit(targetGuid[0]);
4751 data.writeBit(targetGuid[2]);
4752
4753 data.writeBit(casterGuid[0]);
4754 data.writeBit(casterUnitGuid[3]);
4755 data.writeBit(1); // Unk uint8_t
4756
4757
4758
4759 //for (uint32_t i = 0; i < missTypeCount; ++i)
4760 //{
4761 //}
4762
4763 data.writeBit(!hasCastImmunities);
4764 data.writeBit(casterUnitGuid[1]);
4765 data.writeBit(hasVisualChain);
4766 data.writeBit(casterGuid[7]);
4767 data.writeBit(!hasPredictedType);
4768 data.writeBit(casterUnitGuid[0]);
4769
4770 data.flushBits();
4771
4772 data.WriteByteSeq(itemTargetGuid[1]);
4773 data.WriteByteSeq(itemTargetGuid[7]);
4774 data.WriteByteSeq(itemTargetGuid[6]);
4775 data.WriteByteSeq(itemTargetGuid[0]);
4776 data.WriteByteSeq(itemTargetGuid[4]);
4777 data.WriteByteSeq(itemTargetGuid[2]);
4778 data.WriteByteSeq(itemTargetGuid[3]);
4779 data.WriteByteSeq(itemTargetGuid[5]);
4780
4781 //for (uint32_t i = 0; i < hitCount; ++i)
4782 //{
4783 //}
4784
4785 data.WriteByteSeq(targetGuid[4]);
4786 data.WriteByteSeq(targetGuid[5]);
4787 data.WriteByteSeq(targetGuid[1]);
4788 data.WriteByteSeq(targetGuid[7]);
4789 data.WriteByteSeq(targetGuid[6]);
4790 data.WriteByteSeq(targetGuid[3]);
4791 data.WriteByteSeq(targetGuid[2]);
4792 data.WriteByteSeq(targetGuid[0]);
4793
4794 data << uint32_t(m_castTime);
4795
4796 data.WriteByteSeq(unkGuid[4]);
4797 data.WriteByteSeq(unkGuid[5]);
4798 data.WriteByteSeq(unkGuid[3]);
4799 data.WriteByteSeq(unkGuid[2]);
4800 data.WriteByteSeq(unkGuid[1]);
4801 data.WriteByteSeq(unkGuid[6]);
4802 data.WriteByteSeq(unkGuid[7]);
4803 data.WriteByteSeq(unkGuid[0]);
4804
4805
4806
4807
4808 data.WriteByteSeq(casterGuid[4]);
4809
4810 //for (uint32_t i = 0; i < missCount; ++i)
4811 //{
4812 //}
4813
4814 if (hasCastSchoolImmunities)
4815 data << uint32_t(0);
4816
4817 data.WriteByteSeq(casterGuid[2]);
4818
4819 if (hasCastImmunities)
4820 data << uint32_t(0);
4821
4822 if (hasVisualChain)
4823 {
4824 data << uint32_t(0);
4825 data << uint32_t(0);
4826 }
4827
4828
4829 data << uint32_t(0);
4830
4831 data.WriteByteSeq(casterGuid[5]);
4832 data.WriteByteSeq(casterGuid[7]);
4833 data.WriteByteSeq(casterGuid[1]);
4834
4835 data << uint8_t(1);
4836
4837 data.WriteByteSeq(casterUnitGuid[7]);
4838 data.WriteByteSeq(casterUnitGuid[0]);
4839 data.WriteByteSeq(casterGuid[6]);
4840 data.WriteByteSeq(casterGuid[0]);
4841 data.WriteByteSeq(casterUnitGuid[1]);
4842
4843 if (hasAmmoInventoryType)
4844 data << uint8_t(0);
4845
4846 if (hasPredictedHeal)
4847 data << uint32_t(0);
4848
4849 data.WriteByteSeq(casterUnitGuid[6]);
4850 data.WriteByteSeq(casterUnitGuid[3]);
4851
4852 data << uint32_t(m_spellInfo->getId());
4853
4854 if (hasAmmoDisplayId)
4855 data << uint32_t(0);
4856
4857 data.WriteByteSeq(casterUnitGuid[4]);
4858 data.WriteByteSeq(casterUnitGuid[5]);
4859 data.WriteByteSeq(casterUnitGuid[2]);
4860
4861
4862 if (hasPredictedType)
4863 data << uint8_t(0);
4864
4865 data.WriteByteSeq(casterGuid[3]);
4866
4867 m_caster->sendMessageToSet(&data, true);
4868#else
4869 if (!m_caster->IsInWorld())
4870 return;
4871
4872 // If spell has no visuals, it's not channeled and it's triggered, no need to send packet
4873 if (!(getSpellInfo()->isChanneled() || getSpellInfo()->getSpeed() > 0.0f || getSpellInfo()->getSpellVisual(0) != 0 ||
4874 getSpellInfo()->getSpellVisual(1) != 0 || (!m_triggeredSpell && m_triggeredByAura == nullptr)))
4875 return;
4876
4877 // Not sure about the size -Appled
4878 WorldPacket data(SMSG_SPELL_START, 30);
4879
4880 // Set cast flags
4883 castFlags |= SPELL_PACKET_FLAGS_RANGED;
4884
4885#if VERSION_STRING >= WotLK
4886 // Power update for players and their summons
4887 if ((p_caster != nullptr || (u_caster != nullptr && u_caster->getPlayerOwner() != nullptr)) &&
4888 getSpellInfo()->getPowerType() != POWER_TYPE_HEALTH)
4890#endif
4891
4892#if VERSION_STRING >= Cata
4893 // Health update for healing spells
4894 ///\ todo: fix me!
4895 /*for (uint8_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
4896 {
4897 if ((m_castTime > 0 && getSpellInfo()->getEffect(i) == SPELL_EFFECT_HEAL) ||
4898 getSpellInfo()->getEffectApplyAuraName(i) == SPELL_AURA_PERIODIC_HEAL)
4899 {
4900 castFlags |= SPELL_PACKET_FLAGS_HEALTH_UPDATE;
4901 break;
4902 }
4903 }*/
4904#endif
4905
4906 if (i_caster != nullptr)
4907 data << i_caster->GetNewGUID();
4908 else
4909 data << m_caster->GetNewGUID();
4910 data << m_caster->GetNewGUID();
4911
4912#if VERSION_STRING >= WotLK
4913 data << uint8_t(extra_cast_number);
4914 data << uint32_t(getSpellInfo()->getId());
4915 data << uint32_t(castFlags);
4916#else
4917 data << uint32_t(getSpellInfo()->getId());
4918#if VERSION_STRING != Classic
4919 data << uint8_t(extra_cast_number);
4920#endif
4921 data << uint16_t(castFlags);
4922#endif
4923 data << uint32_t(m_timer);
4924#if VERSION_STRING >= Cata
4925 data << uint32_t(m_castTime);
4926#endif
4927
4928 m_targets.write(data);
4929
4930#if VERSION_STRING >= WotLK
4931 if (castFlags & SPELL_PACKET_FLAGS_POWER_UPDATE && u_caster != nullptr)
4932 data << uint32_t(u_caster->getPower(getSpellInfo()->getPowerType()));
4933#endif
4934
4935 if (castFlags & SPELL_PACKET_FLAGS_RANGED)
4937
4938 m_caster->sendMessageToSet(&data, true);
4939#endif
4940}
@ SMSG_SPELL_START
Definition Opcodes.hpp:349
@ SPELL_PACKET_FLAGS_DEFAULT
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SendTameFailure()

void Spell::SendTameFailure ( uint8_t  failure)

Definition at line 1236 of file Spell.Legacy.cpp.

1237{
1238 if (p_caster != nullptr)
1240}
void sendPetTameFailure(uint8_t result) const
Definition Player.cpp:9628
Here is the call graph for this function:
Here is the caller graph for this function:

◆ setForceCritOnTarget()

void Spell::setForceCritOnTarget ( Unit const target)

Definition at line 5902 of file Spell.cpp.

5903{
5904 if (target == nullptr || target->getWorldMap() == nullptr)
5905 return;
5906
5907 m_critTargets.push_back(target->getGuid());
5908}
Here is the call graph for this function:

◆ setItemCaster()

void Spell::setItemCaster ( Item itemCaster)

Definition at line 5654 of file Spell.cpp.

5655{
5656 i_caster = itemCaster;
5657}
Here is the caller graph for this function:

◆ SetSpellFailed()

void Spell::SetSpellFailed ( bool  failed = true)

Definition at line 2921 of file Spell.Legacy.cpp.

2922{
2923 m_Spell_Failed = failed;
2924}
Here is the caller graph for this function:

◆ setTargetConstraintCreature()

void Spell::setTargetConstraintCreature ( Creature _creature)

Definition at line 5699 of file Spell.cpp.

5699{ m_targetConstraintCreature = _creature; }
Here is the caller graph for this function:

◆ setTargetConstraintGameObject()

void Spell::setTargetConstraintGameObject ( GameObject _gameobject)

Definition at line 5702 of file Spell.cpp.

5702{ m_targetConstraintGameObject = _gameobject; }
Here is the caller graph for this function:

◆ setUnitTarget()

void Spell::setUnitTarget ( Unit _unit)

Definition at line 5681 of file Spell.cpp.

5681{ m_unitTarget = _unit; }
Here is the caller graph for this function:

◆ spellEffectActivateObject()

void Spell::spellEffectActivateObject ( uint8_t  effectIndex)

◆ SpellEffectActivateObject()

void Spell::SpellEffectActivateObject ( uint8_t  effectIndex)

Definition at line 4796 of file SpellEffects.Legacy.cpp.

4797{
4798 if (!p_caster)
4799 return;
4800
4801 if (!m_gameObjTarget)
4802 {
4803 sLogger.failure("Spell {} ({}) effect %hhu not handled because no target was found. ", m_spellInfo->getId(), m_spellInfo->getName(), effectIndex);
4804 return;
4805 }
4806
4809
4811
4812#if VERSION_STRING < WotLK
4813 sEventMgr.AddEvent(m_gameObjTarget, &GameObject::setDynamicFlags, static_cast<uint32_t>(0), 0, static_cast<uint32_t>(getDuration()), 1, 0);
4814#elif VERSION_STRING < Mop
4815 sEventMgr.AddEvent(m_gameObjTarget, &GameObject::setDynamicFlags, static_cast<uint16_t>(0), 0, static_cast<uint32_t>(getDuration()), 1, 0);
4816#else
4817 sEventMgr.AddEvent(dynamic_cast<Object*>(m_gameObjTarget), &Object::setDynamicFlags, static_cast<uint16_t>(0), 0, static_cast<uint32_t>(getDuration()), 1, 0);
4818#endif
4819}
@ GO_DYN_FLAG_INTERACTABLE
virtual void OnActivate(Player *)
GameObjectAIScript * GetScript()
void setDynamicFlags(uint16_t dynamicFlags)
Definition Object.cpp:394
Here is the call graph for this function:

◆ spellEffectActivateRunes()

void Spell::spellEffectActivateRunes ( uint8_t  effectIndex)

◆ SpellEffectActivateRunes()

void Spell::SpellEffectActivateRunes ( uint8_t  effectIndex)

Definition at line 6412 of file SpellEffects.Legacy.cpp.

6413{
6414 if (p_caster == nullptr || !p_caster->isClassDeathKnight())
6415 return;
6416
6417 DeathKnight* dk = static_cast<DeathKnight*>(p_caster);
6418
6420 if (!count)
6421 count = 1;
6422
6423 for (uint8_t x = 0; x < MAX_RUNES && count; ++x)
6424 {
6425 if (dk->GetRuneType(x) == getSpellInfo()->getEffectMiscValue(effectIndex) && dk->GetRuneIsUsed(x))
6426 {
6427 dk->ResetRune(x);
6428 --count;
6429 }
6430 }
6431}
bool GetRuneIsUsed(uint8_t slot)
uint8_t GetRuneType(uint8_t slot)
void ResetRune(uint8_t slot)
constexpr auto count() -> size_t
Definition core.h:1222
Here is the call graph for this function:

◆ spellEffectActivateSpec()

void Spell::spellEffectActivateSpec ( uint8_t  effectIndex)

◆ SpellEffectActivateSpec()

void Spell::SpellEffectActivateSpec ( uint8_t  effectIndex)

Definition at line 6190 of file SpellEffects.Legacy.cpp.

6191{
6192#ifndef FT_DUAL_SPEC
6193 return;
6194#else
6195 if (p_caster == nullptr)
6196 return;
6197
6199 {
6201 return;
6202 }
6203 else if (p_caster->getBattleground())
6204 {
6206 {
6208 return;
6209 }
6210 else
6211 {
6214 }
6215 }
6216
6217 // TODO: check if player even have learnt secondary spec
6218 uint8_t NewSpec = p_caster->m_talentActiveSpec == SPEC_PRIMARY ? SPEC_SECONDARY : SPEC_PRIMARY; // Check if primary spec is on or not
6219 p_caster->activateTalentSpec(NewSpec);
6220#endif
6221}
@ SPEC_SECONDARY
Definition Spec.hpp:11
@ SPEC_PRIMARY
Definition Spec.hpp:10
uint8_t m_talentActiveSpec
Definition Player.hpp:1988
void activateTalentSpec(uint8_t specId)
Definition Player.cpp:6237
Here is the call graph for this function:

◆ spellEffectAddComboPoints()

void Spell::spellEffectAddComboPoints ( uint8_t  effectIndex)

◆ SpellEffectAddComboPoints()

void Spell::SpellEffectAddComboPoints ( uint8_t  effectIndex)

Definition at line 4711 of file SpellEffects.Legacy.cpp.

4712{
4713 if (!p_caster)
4714 return;
4715
4717}
void addComboPoints(uint64_t targetGuid, int8_t points)
Definition Player.cpp:5366
Here is the call graph for this function:

◆ spellEffectAddExtraAttacks()

void Spell::spellEffectAddExtraAttacks ( uint8_t  effectIndex)

◆ SpellEffectAddExtraAttacks()

void Spell::SpellEffectAddExtraAttacks ( uint8_t  effectIndex)

Definition at line 2475 of file SpellEffects.Legacy.cpp.

2476{
2477 if (!u_caster)
2478 return;
2480}
int32_t m_extraAttacks
Definition Unit.hpp:1466

◆ spellEffectAddFarsight()

void Spell::spellEffectAddFarsight ( uint8_t  effectIndex)

◆ SpellEffectAddFarsight()

void Spell::SpellEffectAddFarsight ( uint8_t  effectIndex)

Definition at line 4571 of file SpellEffects.Legacy.cpp.

4572{
4573 if (p_caster == nullptr)
4574 return;
4575
4576 auto lv = m_targets.getDestination();
4577 if (!lv.isSet())
4578 {
4579 lv = m_targets.getSource();
4580 }
4581
4583 dynObj->create(u_caster, this, lv, static_cast<uint32_t>(getDuration()), getEffectRadius(effectIndex), DYNAMIC_OBJECT_FARSIGHT_FOCUS);
4585 p_caster->setFarsightGuid(dynObj->getGuid());
4586
4588}
@ DYNAMIC_OBJECT_FARSIGHT_FOCUS
void create(Unit *caster, Spell *pSpell, LocationVector lv, uint32_t duration, float radius, uint32_t type)
void SetInstanceID(int32_t instance)
Definition Object.hpp:663
void setFarsightGuid(uint64_t farsightGuid)
Definition Player.cpp:976
void changeFarsightLocation(Player *plr, DynamicObject *farsight)
DynamicObject * createDynamicObject()
Here is the call graph for this function:

◆ spellEffectAddHonor()

void Spell::spellEffectAddHonor ( uint8_t  effectIndex)

◆ SpellEffectAddHonor()

void Spell::SpellEffectAddHonor ( uint8_t  effectIndex)

Definition at line 3895 of file SpellEffects.Legacy.cpp.

3896{
3897 if (!m_playerTarget) return;
3898
3899 uint32_t val = getSpellInfo()->getEffectBasePoints(effectIndex);
3900
3901 // TODO: is this correct? -Appled
3902 if (getSpellInfo()->getAttributesExB() & ATTRIBUTESEXB_IGNORE_LINE_OF_SIGHT) val /= 10;
3903
3904 val += 1;
3905
3907
3908 m_playerTarget->sendPvpCredit(val, 0, 5);
3909}
static void AddHonorPointsToPlayer(Player *pPlayer, uint32_t uAmount)
void sendPvpCredit(uint32_t honor, uint64_t victimGuid, uint32_t victimRank)
Definition Player.cpp:9885
Here is the call graph for this function:

◆ spellEffectApplyAura()

void Spell::spellEffectApplyAura ( uint8_t  effectIndex)

◆ SpellEffectApplyAura()

void Spell::SpellEffectApplyAura ( uint8_t  effectIndex)

Definition at line 1822 of file SpellEffects.Legacy.cpp.

1823{
1824 if (m_unitTarget == nullptr)
1825 return;
1826
1827#ifdef GM_Z_DEBUG_DIRECTLY
1828 else
1829 {
1830 if (m_unitTarget->isPlayer() && m_unitTarget->IsInWorld() && TO< Player* >(m_unitTarget)->getSession() && TO< Player* >(m_unitTarget)->getSession()->CanUseCommand('z'))
1831 {
1832 sChatHandler.BlueSystemMessage(TO< Player* >(m_unitTarget)->getSession(), "[%sSystem%s] |rSpell::SpellEffectApplyAura: %s EffectApplyAuraName [%u] .", MSG_COLOR_WHITE, MSG_COLOR_LIGHTBLUE, MSG_COLOR_SUBWHITE,
1833 i);
1834 }
1835 }
1836#endif
1837
1838 // avoid map corruption.
1840 return;
1841
1842 //check if we already have stronger aura
1843 Aura* pAura;
1844
1845 auto itr = m_pendingAuras.find(m_unitTarget->getGuid());
1846 //if we do not make a check to see if the aura owner is the same as the caster then we will stack the 2 auras and they will not be visible client sided
1847 if (itr == m_pendingAuras.end())
1848 {
1849 uint32_t Duration = getDuration();
1850
1851 if (ProcedOnSpell) //Warrior's Blood Frenzy
1852 {
1853 switch (getSpellInfo()->getId())
1854 {
1855 //SPELL_HASH_BLOOD_FRENZY
1856 case 16952:
1857 case 16954:
1858 case 29836:
1859 case 29859:
1860 case 30069:
1861 case 30070:
1862 {
1863 const auto motherSpellDuration = sSpellDurationStore.lookupEntry(ProcedOnSpell->getDurationIndex());
1864 if (motherSpellDuration != nullptr)
1865 {
1866 if (motherSpellDuration->Duration3 > 0)
1867 Duration = motherSpellDuration->Duration3;
1868 else if (motherSpellDuration->Duration2 > 0)
1869 Duration = motherSpellDuration->Duration2;
1870 else
1871 Duration = motherSpellDuration->Duration1;
1872 }
1873 } break;
1874 }
1875 }
1876
1877 // Handle diminishing returns, if it should be resisted, it'll make duration 0 here.
1878 if (!(getSpellInfo()->isPassive())) // Passive
1879 {
1881 }
1882
1883 if (!Duration)
1884 {
1886 return;
1887 }
1888
1889 std::unique_ptr<Aura> auraHolder;
1891 auraHolder = sSpellMgr.newAura(getSpellInfo(), Duration, g_caster->getUnitOwner(), m_unitTarget, m_triggeredSpell, i_caster);
1892 else
1893 auraHolder = sSpellMgr.newAura(getSpellInfo(), Duration, m_caster, m_unitTarget, m_triggeredSpell, i_caster);
1894
1895 auraHolder->pSpellId = pSpellId; //this is required for triggered spells
1896 auraHolder->m_castedItemId = castedItemId;
1897
1898 const auto [itr, _] = m_pendingAuras.try_emplace(m_unitTarget->getGuid(), 0, std::move(auraHolder));
1899 pAura = itr->second.aur.get();
1900 }
1901 else
1902 {
1903 pAura = itr->second.aur.get();
1904 }
1905 switch (m_spellInfo->getId())
1906 {
1907 case 27907:
1908 {
1909 if (m_unitTarget->getEntry() == 15941)
1910 {
1911 m_unitTarget->sendChatMessage(CHAT_MSG_MONSTER_SAY, LANG_UNIVERSAL, "What? Oh, not this again!");
1912 }
1913 else if (m_unitTarget->getEntry() == 15945)
1914 {
1915 m_unitTarget->sendChatMessage(CHAT_MSG_MONSTER_SAY, LANG_UNIVERSAL, "You can't do this to me! We had a deal!");
1916 }
1917 else
1918 {
1920 return;
1921 }
1922 }break;
1923 case 28880:
1924 {
1925 if (!p_caster)
1926 break;
1927
1928 if (m_unitTarget->getEntry() == 16483)
1929 {
1932 static const char* testo[12] = { "None", "Warrior", "Paladin", "Hunter", "Rogue", "Priest", "Death Knight", "Shaman", "Mage", "Warlock", "None", "Druid" };
1933 char msg[150];
1934 snprintf(msg, 150, "Many thanks to you %s. I'd best get to the crash site and see how I can help out. Until we meet again...", testo[p_caster->getClass()]);
1936 ((Creature*)m_unitTarget)->Despawn(900000, 300000);
1937 }
1938 }break;
1939 case 38177:
1940 {
1941 if (!p_caster)
1942 break;
1943
1944 if (m_unitTarget->getEntry() == 21387)
1945 {
1946 ((Creature*)m_unitTarget)->Despawn(5000, 360000);
1947 p_caster->castSpell(p_caster, 38178, true);
1948 }
1949 else
1950 {
1952 return;
1953 }
1954 }break;
1955 }
1956
1957 if (!pAura)
1958 {
1959 sLogger.failure("Warning tried to add Aura Effect for nonexistant Aura returning!");
1960 return;
1961 }
1962
1963 pAura->addAuraEffect(static_cast<AuraEffect>(getSpellInfo()->getEffectApplyAuraName(effectIndex)), damage, getSpellInfo()->getEffectMiscValue(effectIndex), effectPctModifier[effectIndex], isEffectDamageStatic[effectIndex], effectIndex);
1964}
#define sChatHandler
#define MSG_COLOR_WHITE
#define MSG_COLOR_SUBWHITE
@ CHAT_MSG_MONSTER_SAY
#define MSG_COLOR_LIGHTBLUE
@ LANG_UNIVERSAL
@ STANDSTATE_STAND
uint32_t getDurationIndex() const
void setStandState(uint8_t standState)
Definition Unit.cpp:1366
void applyDiminishingReturnTimer(uint32_t *duration, SpellInfo const *spell)
Definition Unit.cpp:3447
void sendChatMessage(uint8_t type, uint32_t language, std::string msg, Unit *receiver=nullptr, uint32_t sessionLanguage=0)
Definition Unit.cpp:6851
Here is the call graph for this function:

◆ spellEffectApplyEnemyAA()

void Spell::spellEffectApplyEnemyAA ( uint8_t  effectIndex)

◆ SpellEffectApplyEnemyAA()

void Spell::SpellEffectApplyEnemyAA ( uint8_t  effectIndex)

Definition at line 5948 of file SpellEffects.Legacy.cpp.

5949{
5950 ApplyAreaAura(effectIndex);
5951}
void ApplyAreaAura(uint8_t effectIndex)
Here is the call graph for this function:

◆ spellEffectApplyFriendAA()

void Spell::spellEffectApplyFriendAA ( uint8_t  effectIndex)

◆ SpellEffectApplyFriendAA()

void Spell::SpellEffectApplyFriendAA ( uint8_t  effectIndex)

Definition at line 5943 of file SpellEffects.Legacy.cpp.

5944{
5945 ApplyAreaAura(effectIndex);
5946}
Here is the call graph for this function:

◆ spellEffectApplyGroupAA()

void Spell::spellEffectApplyGroupAA ( uint8_t  effectIndex)

◆ SpellEffectApplyGroupAA()

void Spell::SpellEffectApplyGroupAA ( uint8_t  effectIndex)

Definition at line 3655 of file SpellEffects.Legacy.cpp.

3656{
3657 ApplyAreaAura(effectIndex);
3658}
Here is the call graph for this function:

◆ spellEffectApplyOwnerAA()

void Spell::spellEffectApplyOwnerAA ( uint8_t  effectIndex)

◆ SpellEffectApplyOwnerAA()

void Spell::SpellEffectApplyOwnerAA ( uint8_t  effectIndex)

Definition at line 6036 of file SpellEffects.Legacy.cpp.

6037{
6038 ApplyAreaAura(effectIndex);
6039}
Here is the call graph for this function:

◆ spellEffectApplyPetAA()

void Spell::spellEffectApplyPetAA ( uint8_t  effectIndex)

◆ SpellEffectApplyPetAA()

void Spell::SpellEffectApplyPetAA ( uint8_t  effectIndex)

Definition at line 5515 of file SpellEffects.Legacy.cpp.

5516{
5517 ApplyAreaAura(effectIndex);
5518}
Here is the call graph for this function:

◆ spellEffectApplyRaidAA()

void Spell::spellEffectApplyRaidAA ( uint8_t  effectIndex)

◆ SpellEffectApplyRaidAA()

void Spell::SpellEffectApplyRaidAA ( uint8_t  effectIndex)

Definition at line 4415 of file SpellEffects.Legacy.cpp.

4416{
4417 ApplyAreaAura(effectIndex);
4418}
Here is the call graph for this function:

◆ spellEffectAttackMe()

void Spell::spellEffectAttackMe ( uint8_t  effectIndex)

◆ SpellEffectAttackMe()

void Spell::SpellEffectAttackMe ( uint8_t  effectIndex)

Definition at line 5415 of file SpellEffects.Legacy.cpp.

5416{
5417 if (!m_unitTarget || !m_unitTarget->isAlive())
5418 return;
5419
5421 return;
5422
5424 if (mgr.getCurrentVictim() == u_caster)
5425 return;
5426
5427 if (!mgr.isThreatListEmpty())
5428 {
5429 mgr.addThreat(u_caster, 20.0f, nullptr, false, false);
5430 // Set threat equal to highest threat currently on target
5432
5433 // Call on AIInterface
5436 }
5437}
void eventOnTaunt(Unit *pUnit)
Unit * getCurrentVictim()
void matchUnitThreatToHighestThreat(Unit *target)
bool isThreatListEmpty(bool includeOffline=false) const
Here is the call graph for this function:

◆ spellEffectBind()

void Spell::spellEffectBind ( uint8_t  effectIndex)

◆ SpellEffectBind()

void Spell::SpellEffectBind ( uint8_t  effectIndex)

Definition at line 2373 of file SpellEffects.Legacy.cpp.

2374{
2376 return;
2377
2378 WorldPacket data(45);
2379 uint32_t areaid = m_playerTarget->getZoneId();
2380 uint32_t mapid = m_playerTarget->GetMapId();
2381 if (getSpellInfo()->getEffectMiscValue(effectIndex))
2382 {
2383 areaid = getSpellInfo()->getEffectMiscValue(effectIndex);
2385 if (!at)
2386 return;
2387 mapid = at->map_id;
2388 }
2389
2391
2393
2395}
uint32_t getBindMapId() const
Definition Player.cpp:7817
LocationVector getBindPosition() const
Definition Player.cpp:7816
void setBindPoint(float x, float y, float z, float o, uint32_t mapId, uint32_t zoneId)
Definition Player.cpp:7809
uint32_t getBindZoneId() const
Definition Player.cpp:7818
Here is the call graph for this function:

◆ spellEffectBlock()

void Spell::spellEffectBlock ( uint8_t  effectIndex)

◆ SpellEffectBlock()

void Spell::SpellEffectBlock ( uint8_t  effectIndex)

Definition at line 2497 of file SpellEffects.Legacy.cpp.

2498{
2499 //i think this actually enables the skill to be able to block melee+ranged attacks
2500 //value is static and sets value directly which will be modified by other factors
2501 // if (m_unitTarget->isPlayer())
2502 // m_unitTarget->SetFloatValue(PLAYER_BLOCK_PERCENTAGE,damage);
2503}

◆ spellEffectBuildingDamage()

void Spell::spellEffectBuildingDamage ( uint8_t  effectIndex)

◆ SpellEffectBuildingDamage()

void Spell::SpellEffectBuildingDamage ( uint8_t  effectIndex)

Definition at line 4821 of file SpellEffects.Legacy.cpp.

4822{
4823 if (m_gameObjTarget == nullptr)
4824 {
4825 sLogger.failure("Spell {} ({}) effect %hhu not handled because no target was found. ", m_spellInfo->getId(), m_spellInfo->getName(), effectIndex);
4826 return;
4827 }
4828
4830 return;
4831
4832 if (u_caster == nullptr)
4833 return;
4834
4835 uint32_t spellDamage = m_spellInfo->getEffectBasePoints(effectIndex) + 1;
4836 Unit* controller = nullptr;
4837#ifdef FT_VEHICLES
4838 if (u_caster->getVehicle() != nullptr)
4840#endif
4841
4842 if (controller == nullptr)
4843 controller = u_caster;
4844
4845 // Baaaam
4847 dgo->Damage(spellDamage, u_caster->getGuid(), controller->getGuid(), m_spellInfo->getId());
4848}
@ GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING
void Damage(uint32_t damage, uint64_t AttackerGUID, uint64_t ControllerGUID, uint32_t SpellID)
Here is the call graph for this function:

◆ spellEffectCharge()

void Spell::spellEffectCharge ( uint8_t  effectIndex)

◆ SpellEffectCharge()

void Spell::SpellEffectCharge ( uint8_t  effectIndex)

Definition at line 4988 of file SpellEffects.Legacy.cpp.

4989{
4990 if (m_unitTarget == nullptr || !m_unitTarget->isAlive())
4991 return;
4992
4993 float speed = G3D::fuzzyGt(getSpellInfo()->getSpeed(), 0.0f) ? getSpellInfo()->getSpeed() : SPEED_CHARGE;
4994
4996 u_caster->getMovementManager()->moveCharge(pos, speed);
4997}
#define SPEED_CHARGE
void moveCharge(LocationVector const &pos, float speed=SPEED_CHARGE, uint32_t id=EVENT_CHARGE, bool generatePath=false)
float getRelativeAngle(Object const *obj)
Definition Object.hpp:526
LocationVector getFirstCollisionPosition(float dist, float angle)
Definition Object.cpp:4920
MovementManager * getMovementManager()
Definition Unit.hpp:655
bool fuzzyGt(double a, double b)
Definition g3dmath.h:865
Here is the call graph for this function:

◆ spellEffectClearQuest()

void Spell::spellEffectClearQuest ( uint8_t  effectIndex)

◆ SpellEffectClearQuest()

void Spell::SpellEffectClearQuest ( uint8_t  effectIndex)

Definition at line 4400 of file SpellEffects.Legacy.cpp.

4401{
4402 if (m_playerTarget == nullptr)
4403 {
4404 sLogger.failure("Spell {} ({}) was not casted on Player, but Spell requires Player to be a target.", m_spellInfo->getId(), m_spellInfo->getName());
4405 return;
4406 }
4407
4408 uint32_t questid1 = m_spellInfo->getEffectBasePoints(effectIndex);
4409 uint32_t questid2 = m_spellInfo->getEffectMiscValue(effectIndex);
4410
4411 m_playerTarget->clearQuest(questid1);
4412 m_playerTarget->clearQuest(questid2);
4413}
void clearQuest(uint32_t questId)
Definition Player.cpp:8945
Here is the call graph for this function:

◆ spellEffectCreateHouse()

void Spell::spellEffectCreateHouse ( uint8_t  effectIndex)

◆ SpellEffectCreateHouse()

void Spell::SpellEffectCreateHouse ( uint8_t  effectIndex)

Definition at line 4719 of file SpellEffects.Legacy.cpp.

4720{
4721}

◆ spellEffectCreateItem()

void Spell::spellEffectCreateItem ( uint8_t  effectIndex)

◆ SpellEffectCreateItem()

void Spell::SpellEffectCreateItem ( uint8_t  effectIndex)

Definition at line 2505 of file SpellEffects.Legacy.cpp.

2506{
2507 uint32_t spellid = m_spellInfo->getId();
2508
2509 if (m_playerTarget == nullptr)
2510 {
2511 sLogger.failure("Spell {} ({}) has a create item effect but no player target!", spellid, m_spellInfo->getName());
2512 return;
2513 }
2514
2515
2516 uint32_t itemid = m_spellInfo->getEffectItemType(effectIndex);
2517 uint32_t count = 0;
2518 uint32_t basecount = m_spellInfo->getEffectDieSides(effectIndex);
2519 uint32_t difference = m_spellInfo->getEffectBasePoints(effectIndex);
2520
2521 if (itemid == 0)
2522 {
2523 sLogger.failure("Spell {} ({}) has a create item effect but no itemid to add, Spell needs to be fixed!", spellid, m_spellInfo->getName());
2524 return;
2525 }
2526
2527 ItemProperties const* m_itemProto = sMySQLStore.getItemProperties(itemid);
2528 if (m_itemProto == nullptr)
2529 {
2530 sLogger.failure("Spell {} ({}) has a create item effect but the itemid is invalid!", spellid, m_spellInfo->getName());
2531 return;
2532 }
2533
2534 if (difference > basecount)
2535 {
2536 count = basecount + difference;
2537
2538 }
2539 else
2540 {
2541 uint32_t mincount = basecount - difference;
2542 uint32_t maxcount = basecount + difference;
2543 uint32_t variablecount = maxcount - mincount;
2544 uint32_t randcount = Util::getRandomUInt(variablecount);
2545
2546 count = mincount + randcount;
2547 }
2548
2549 uint32_t countperlevel = static_cast<uint32_t>(std::round(m_spellInfo->getEffectRealPointsPerLevel(effectIndex)));
2550
2551 if (countperlevel != 0)
2552 {
2554 uint32_t countforlevel = leveldiff * countperlevel;
2555
2556 count += countforlevel;
2557 }
2558
2559 // Make sure the count is at least 1 (no need to generate warning from this)
2560 count = std::max(1u, count);
2561
2562 if (p_caster != nullptr)
2563 {
2564 auto skill_line_ability = sSpellMgr.getFirstSkillEntryForSpell(spellid);
2565
2566 // potions learned by discovery variables
2567 uint32_t cast_chance = 5;
2568 uint32_t learn_spell = 0;
2569
2570 // tailoring specializations get +1 cloth bonus
2571 switch (spellid)
2572 {
2573 case 36686: //Shadowcloth
2574 if (p_caster->hasSpell(26801)) count++;
2575 break;
2576
2577 case 26751: // Primal Mooncloth
2578 if (p_caster->hasSpell(26798)) count++;
2579 break;
2580
2581 case 31373: //Spellcloth
2582 if (p_caster->hasSpell(26797)) count++;
2583 break;
2584 }
2585
2586 if ((skill_line_ability != nullptr) && (skill_line_ability->skilline == SKILL_ALCHEMY))
2587 {
2588 //Potion Master
2589 if (m_itemProto->Name.compare("Potion"))
2590 {
2591 if (p_caster->hasSpell(28675))
2592 while (Util::checkChance(20) && (count < 5))
2593 count++;
2594
2595 // Super Rejuvenation Potion
2596 cast_chance = 2;
2597 learn_spell = 28586;
2598 }
2599
2600 //Elixir Master
2601 if (m_itemProto->Name.compare("Elixir") || m_itemProto->Name.compare("Flask"))
2602 {
2603 if (p_caster->hasSpell(28677))
2604 while (Util::checkChance(20) && (count < 5))
2605 count++;
2606
2607 uint32_t spList[] = { 28590, 28587, 28588, 28591, 28589 };
2608 cast_chance = 2;
2609 learn_spell = spList[Util::getRandomUInt(4)];
2610 }
2611
2612 //Transmutation Master
2613 if (m_spellInfo->getCategory() == 310)
2614 {
2615
2616 //rate for primal might is lower than for anything else
2617 if (m_spellInfo->getId() == 29688)
2618 {
2619 if (p_caster->hasSpell(28672))
2620 while (Util::checkChance(40) && (count < 5))
2621 count++;
2622 }
2623 else
2624 {
2625 if (p_caster->hasSpell(28672))
2626 while (Util::checkChance(20) && (count < 5))
2627 count++;
2628 }
2629
2630 uint32_t spList[] = { 28581, 28585, 28585, 28584, 28582, 28580 };
2631 cast_chance = 5;
2632 learn_spell = spList[Util::getRandomUInt(5)];
2633 }
2634 }
2635
2636 if (!m_playerTarget->getItemInterface()->AddItemById(itemid, count, 0))
2637 {
2639 return;
2640 }
2641
2642 if (p_caster != nullptr)
2643 {
2644 //random discovery by crafter item id
2645 switch (itemid)
2646 {
2647 case 22845: //Major Arcane Protection Potion
2648 cast_chance = 20;
2649 learn_spell = 41458;
2650 break;
2651
2652 case 22841: //Major Fire Protection Potion
2653 cast_chance = 20;
2654 learn_spell = 41500;
2655 break;
2656
2657 case 22842: //Major Frost Protection Potion
2658 cast_chance = 20;
2659 learn_spell = 41501;
2660 break;
2661
2662 case 22847: //Major Holy Protection Potion
2663 // there is none
2664 break;
2665
2666 case 22844: //Major Nature Protection Potion
2667 cast_chance = 20;
2668 learn_spell = 41502;
2669 break;
2670
2671 case 22846: //Major Shadow Protection Potion
2672 cast_chance = 20;
2673 learn_spell = 41503;
2674 break;
2675 }
2676
2677 if ((learn_spell != 0) && (p_caster->getLevel() > 60) && !p_caster->hasSpell(learn_spell) && Util::checkChance(cast_chance))
2678 {
2679 SpellInfo const* dspellproto = sSpellMgr.getSpellInfo(learn_spell);
2680
2681 if (dspellproto != nullptr)
2682 {
2683 p_caster->broadcastMessage("%sDISCOVERY! You discovered the %s !|r", MSG_COLOR_YELLOW, dspellproto->getName().c_str());
2684 p_caster->addSpell(learn_spell);
2685 }
2686 else
2687 {
2688 sLogger.failure("Spell {} ({}) Effect Index %hhu tried to teach a non-existing Spell {} in {}:{}", spellid, m_spellInfo->getName(), effectIndex, learn_spell, __FILE__, __LINE__);
2689 }
2690 }
2691 }
2692
2693 if (skill_line_ability != nullptr)
2694 {
2695 const auto skillLine = static_cast<uint16_t>(skill_line_ability->skilline);
2696 DetermineSkillUp(skillLine);
2697
2698 uint32_t discovered_recipe = 0;
2699
2700 for (auto itr = sMySQLStore._professionDiscoveryStore.begin(); itr != sMySQLStore._professionDiscoveryStore.end(); ++itr)
2701 {
2702 const auto& pf = *itr;
2703 if (spellid == pf->SpellId && p_caster->getSkillLineCurrent(skillLine) >= pf->SkillValue && !p_caster->hasSpell(pf->SpellToDiscover) && Util::checkChance(pf->Chance))
2704 {
2705 discovered_recipe = pf->SpellToDiscover;
2706 break;
2707 }
2708 }
2709
2710 // if something was discovered teach player that recipe and broadcast message
2711 if (discovered_recipe != 0)
2712 {
2713 SpellInfo const* se = sSpellMgr.getSpellInfo(discovered_recipe);
2714
2715 if (se != nullptr)
2716 {
2717 p_caster->addSpell(discovered_recipe);
2718
2719 char msg[256];
2720 sprintf(msg, "%sDISCOVERY! %s has discovered how to create %s.|r", MSG_COLOR_GOLD, p_caster->getName().c_str(), se->getName().c_str());
2721
2723 }
2724 else
2725 {
2726 sLogger.failure("Spell {} ({}) Effect index %hhu tried to teach a non-existing Spell {} in {}:{}", spellid, m_spellInfo->getName(), effectIndex, learn_spell, __FILE__, __LINE__);
2727 }
2728 }
2729 }
2730 }
2731 else
2732 {
2733 if (!m_playerTarget->getItemInterface()->AddItemById(itemid, count, 0))
2735 }
2736}
@ CHAT_MSG_SYSTEM
#define MSG_COLOR_GOLD
#define MSG_COLOR_YELLOW
@ SKILL_ALCHEMY
Definition Skill.hpp:72
@ SPELL_FAILED_TOO_MANY_OF_ITEM
utf8_string getName() const
Definition Player.cpp:2639
bool hasSpell(uint32_t spellId) const
Definition Player.cpp:3925
void broadcastMessage(const char *Format,...)
Definition Player.cpp:6552
uint32_t getBaseLevel() const
int32_t getEffectDieSides(uint8_t idx) const
uint32_t getEffectItemType(uint8_t idx) const
uint32_t getMaxLevel() const
uint32_t getCategory() const
float getEffectRealPointsPerLevel(uint8_t idx) const
void DetermineSkillUp()
void sendChatMessageToCellPlayers(Object *obj, WorldPacket *packet, uint32_t cell_radius, uint32_t langpos, int32_t lang, WorldSession *originator)
auto sprintf(const S &fmt, const T &... args) -> std::basic_string< Char >
Definition printf.h:612
Here is the call graph for this function:

◆ spellEffectCreateItem2()

void Spell::spellEffectCreateItem2 ( uint8_t  effectIndex)

◆ SpellEffectCreateItem2()

void Spell::SpellEffectCreateItem2 ( uint8_t  effectIndex)
Todo:
This spell effect has also a misc value - meaning is unknown yet
Todo:
Finish this

Definition at line 6110 of file SpellEffects.Legacy.cpp.

6111{
6112 ///\todo This spell effect has also a misc value - meaning is unknown yet
6113 if (p_caster == nullptr)
6114 return;
6115
6116 uint32_t new_item_id = getSpellInfo()->getEffectItemType(effectIndex);
6117
6118 if (new_item_id != 0)
6119 {
6120 // create item
6121 CreateItem(new_item_id);
6122 }
6123 else if (i_caster)
6124 {
6125 // provide player with item loot (clams)
6126 ///\todo Finish this
6127 }
6128}
void CreateItem(uint32_t itemId)
Here is the call graph for this function:

◆ spellEffectCreatePet()

void Spell::spellEffectCreatePet ( uint8_t  effectIndex)

◆ SpellEffectCreatePet()

void Spell::SpellEffectCreatePet ( uint8_t  effectIndex)

Definition at line 6041 of file SpellEffects.Legacy.cpp.

6042{
6043 if (!m_playerTarget)
6044 return;
6045
6046 if (m_playerTarget->getPet())
6048
6049 CreatureProperties const* ci = sMySQLStore.getCreatureProperties(getSpellInfo()->getEffectMiscValue(effectIndex));
6050 if (ci)
6051 {
6052 const auto pet = sObjectMgr.createPet(getSpellInfo()->getEffectMiscValue(effectIndex), nullptr);
6053 if (!pet->createAsSummon(ci, nullptr, m_playerTarget, m_playerTarget->GetPosition(), 0, m_spellInfo, effectIndex, PET_TYPE_HUNTER))
6054 {
6055 pet->DeleteMe();//CreateAsSummon() returns false if an error occurred.
6056 }
6057 }
6058}
@ PET_TYPE_HUNTER
void unSummon() override
Definition Pet.cpp:422
Here is the call graph for this function:

◆ spellEffectDefense()

void Spell::spellEffectDefense ( uint8_t  effectIndex)

Definition at line 576 of file SpellEffects.Legacy.cpp.

577{
578 if (m_playerTarget == nullptr)
579 return;
580
583}
@ SKILL_DEFENSE
Definition Skill.hpp:38
void addSkillLine(uint16_t skillLine, uint16_t currentValue, uint16_t maxValue, bool noSpellLearning=false, bool initializeProfession=false)
Definition Player.cpp:4760
Here is the call graph for this function:

◆ spellEffectDestroyAllTotems()

void Spell::spellEffectDestroyAllTotems ( uint8_t  effectIndex)

◆ SpellEffectDestroyAllTotems()

void Spell::SpellEffectDestroyAllTotems ( uint8_t  effectIndex)

Definition at line 5326 of file SpellEffects.Legacy.cpp.

5327{
5328
5329 if (p_caster == nullptr || !p_caster->IsInWorld())
5330 return;
5331
5332 uint32_t RetreivedMana = 0;
5333 uint32_t refundpercent = m_spellInfo->getEffectBasePoints(effectIndex) + 1;
5334
5336 {
5337 const auto* totem = p_caster->getSummonInterface()->getSummonInSlot(static_cast<SummonSlot>(i));
5338 if (totem == nullptr || !totem->isTotem())
5339 continue;
5340
5341 const auto spellid = totem->getCreatedBySpellId();
5342 SpellInfo const* sp = sSpellMgr.getSpellInfo(spellid);
5343
5344 if (sp != nullptr)
5345 {
5346 uint32_t cost = 0;
5347
5348 if (sp->getManaCostPercentage() != 0)
5349 cost = (p_caster->getBaseMana() * sp->getManaCostPercentage()) / 100;
5350 else
5351 cost = sp->getManaCost();
5352
5353 RetreivedMana += static_cast<uint32_t>((cost * refundpercent) / 100.0f);
5354 }
5355 }
5356
5359}
SummonSlot
@ SUMMON_SLOT_TOTEM_AIR
@ SUMMON_SLOT_TOTEM_FIRE
uint32_t getManaCost() const
uint32_t getManaCostPercentage() const
Summon * getSummonInSlot(SummonSlot slot) const
void killAllTotems() const
uint32_t getBaseMana() const
Definition Unit.cpp:1470
SummonHandler * getSummonInterface()
Definition Unit.cpp:7943
void energize(Unit *target, uint32_t spellId, uint32_t amount, PowerType type, bool sendPacket=true)
Definition Unit.cpp:6680
Here is the call graph for this function:

◆ spellEffectDisenchant()

void Spell::spellEffectDisenchant ( uint8_t  effectIndex)

◆ SpellEffectDisenchant()

void Spell::SpellEffectDisenchant ( uint8_t  effectIndex)

Definition at line 5077 of file SpellEffects.Legacy.cpp.

5078{
5079 if (!p_caster)
5080 return;
5081
5083 if (!it)
5084 {
5086 return;
5087 }
5088
5089 //Fill disenchanting loot
5091 if (!it->m_loot)
5092 {
5093 it->m_loot = std::make_unique<Loot>();
5094 sLootMgr.fillItemLoot(p_caster, it->m_loot.get(), it->getEntry(), 0);
5095 }
5096
5097 sLogger.debugFlag(AscEmu::Logging::LF_SPELL_EFF, "Successfully disenchanted item {}", uint32_t(it->getEntry()));
5099
5100 //We can increase Enchanting skill up to 60
5102 if (skill && skill < 60)
5103 {
5104 if (Util::checkChance(100.0f - skill * 0.75f))
5105 {
5106 auto SkillUp = static_cast<uint16_t>(Util::float2int32(1.0f * worldConfig.getFloatRate(RATE_SKILLRATE)));
5107 if (skill + SkillUp > 60)
5108 SkillUp = 60 - skill;
5109
5111 }
5112 }
5113 if (it == i_caster)
5114 i_caster = nullptr;
5115}
@ LOOT_DISENCHANTING
std::unique_ptr< Loot > m_loot
Definition Item.hpp:256
void sendLoot(uint64_t guid, uint8_t loot_type, uint32_t mapId)
Definition Player.cpp:10791
void setLootGuid(const uint64_t &guid)
Definition Player.cpp:10788
Here is the call graph for this function:

◆ spellEffectDismissPet()

void Spell::spellEffectDismissPet ( uint8_t  effectIndex)

◆ SpellEffectDismissPet()

void Spell::SpellEffectDismissPet ( uint8_t  effectIndex)

Definition at line 5168 of file SpellEffects.Legacy.cpp.

5169{
5170 // remove pet.. but don't delete so it can be called later
5171 if (!p_caster) return;
5172
5173 Pet* pPet = p_caster->getPet();
5174 if (!pPet) return;
5175 pPet->unSummon();
5176}
Here is the call graph for this function:

◆ spellEffectDispel()

void Spell::spellEffectDispel ( uint8_t  effectIndex)

◆ SpellEffectDispel()

void Spell::SpellEffectDispel ( uint8_t  effectIndex)

Definition at line 3792 of file SpellEffects.Legacy.cpp.

3793{
3794 if (u_caster == nullptr || m_unitTarget == nullptr)
3795 return;
3796
3797 uint16_t start, end;
3798
3799 if (u_caster->isValidTarget(m_unitTarget) || getSpellInfo()->getEffectMiscValue(effectIndex) == DISPEL_STEALTH) // IsAttackable returns false for stealthed
3800 {
3803 if (m_unitTarget->m_schoolImmunityList[getSpellInfo()->getFirstSchoolFromSchoolMask()])
3804 return;
3805 }
3806 else
3807 {
3810 }
3811
3812 SpellInfo const* aursp;
3813 std::list< uint32_t > dispelledSpells;
3814 bool finish = false;
3815
3816 for (uint16_t x = start; x < end; x++)
3817 {
3818 if (auto* const aur = m_unitTarget->getAuraWithAuraSlot(x))
3819 {
3820 bool AuraRemoved = false;
3821 aursp = aur->getSpellInfo();
3822
3823 //Nothing can dispel resurrection sickness;
3824 if (!aur->IsPassive() && !(aursp->getAttributes() & ATTRIBUTES_IGNORE_INVULNERABILITY))
3825 {
3826 if (getSpellInfo()->getDispelType() == DISPEL_ALL)
3827 {
3828 dispelledSpells.push_back(aursp->getId());
3829
3830 aur->removeAura(AURA_REMOVE_ON_DISPEL);
3831 AuraRemoved = true;
3832
3833 if (--damage <= 0)
3834 finish = true;
3835 }
3836 else if (static_cast<int32_t>(aursp->getDispelType()) == getSpellInfo()->getEffectMiscValue(effectIndex))
3837 {
3838 dispelledSpells.push_back(aursp->getId());
3839
3840 aur->removeAura(AURA_REMOVE_ON_DISPEL);
3841 AuraRemoved = true;
3842
3843 if (--damage <= 0)
3844 finish = true;
3845 }
3846
3847 if (AuraRemoved)
3848 {
3849 switch (aursp->getId())
3850 {
3851 //SPELL_HASH_UNSTABLE_AFFLICTION
3852 case 30108:
3853 case 30404:
3854 case 30405:
3855 case 31117:
3856 case 34438:
3857 case 34439:
3858 case 35183:
3859 case 43522:
3860 case 43523:
3861 case 47841:
3862 case 47843:
3863 case 65812:
3864 case 65813:
3865 case 68154:
3866 case 68155:
3867 case 68156:
3868 case 68157:
3869 case 68158:
3870 case 68159:
3871 {
3872 const auto spellInfo = sSpellMgr.getSpellInfo(31117);
3873 Spell* spell = sSpellMgr.newSpell(u_caster, spellInfo, true, nullptr);
3874 spell->forced_basepoints->set(0, (aursp->calculateEffectValue(0)) * 9); //damage effect
3875 spell->ProcedOnSpell = getSpellInfo();
3876 spell->pSpellId = aursp->getId();
3877 SpellCastTargets targets(u_caster->getGuid());
3878 spell->prepare(&targets);
3879 } break;
3880 }
3881 }
3882 }
3883 if (finish)
3884 break;
3885 }
3886 }
3887
3888 // send spell dispell log packet
3889 if (!dispelledSpells.empty())
3890 {
3891 m_caster->sendMessageToSet(SmsgSpellDispellLog(m_caster->getGuid(), m_unitTarget->getGuid(), getSpellInfo()->getId(), dispelledSpells).serialise().get(), true);
3892 }
3893}
@ AURA_REMOVE_ON_DISPEL
@ DISPEL_STEALTH
Aura * getAuraWithAuraSlot(uint16_t auraSlot) const
Definition Unit.cpp:4944
@ POSITIVE_SLOT_START
Definition AuraSlots.hpp:21
@ POSITIVE_SLOT_END
Definition AuraSlots.hpp:22
@ NEGATIVE_SLOT_START
Definition AuraSlots.hpp:24
@ NEGATIVE_SLOT_END
Definition AuraSlots.hpp:25
Here is the call graph for this function:

◆ spellEffectDispelMechanic()

void Spell::spellEffectDispelMechanic ( uint8_t  effectIndex)

◆ SpellEffectDispelMechanic()

void Spell::SpellEffectDispelMechanic ( uint8_t  effectIndex)

Definition at line 5251 of file SpellEffects.Legacy.cpp.

5252{
5253 if (!m_unitTarget || !m_unitTarget->isAlive())
5254 return;
5255
5256 m_unitTarget->removeAllAurasBySpellMechanic(static_cast<SpellMechanic>(getSpellInfo()->getEffectMiscValue(effectIndex)), false);
5257}
void removeAllAurasBySpellMechanic(SpellMechanic mechanic, bool negativeOnly=true)
Definition Unit.cpp:5331
Here is the call graph for this function:

◆ spellEffectDistract()

void Spell::spellEffectDistract ( uint8_t  effectIndex)

◆ SpellEffectDistract()

void Spell::SpellEffectDistract ( uint8_t  effectIndex)

Definition at line 4524 of file SpellEffects.Legacy.cpp.

4525{
4526 //spellId 1725 Distract:Throws a distraction attracting the all monsters for ten sec's
4527 if (!m_unitTarget || !m_unitTarget->isAlive())
4528 return;
4529
4531 {
4532 // m_unitTarget->getAIInterface()->MoveTo(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, 0);
4533 uint32_t Stare_duration = getDuration();
4534 if (Stare_duration > 30 * 60 * 1000)
4535 Stare_duration = 10000;//if we try to stare for more then a half an hour then better not stare at all :P (bug)
4536
4537 auto destination = m_targets.getDestination();
4538 float newo = m_unitTarget->calcRadAngle(m_unitTarget->GetPositionX(), m_unitTarget->GetPositionY(), destination.x, destination.y);
4539
4540 m_unitTarget->pauseMovement(Stare_duration);
4541 m_unitTarget->setFacing(newo);
4542 }
4543
4544 //Smoke Emitter 164870
4545 //Smoke Emitter Big 179066
4546 //Unit Field Target of
4547}
float calcRadAngle(float Position1X, float Position1Y, float Position2X, float Position2Y)
Definition Object.cpp:3700
void setFacing(float newo)
Definition Unit.cpp:2446
Here is the call graph for this function:

◆ spellEffectDodge()

void Spell::spellEffectDodge ( uint8_t  effectIndex)

◆ SpellEffectDodge()

void Spell::SpellEffectDodge ( uint8_t  effectIndex)

Definition at line 2482 of file SpellEffects.Legacy.cpp.

2483{
2484 //i think this actually enables the skill to be able to dodge melee+ranged attacks
2485 //value is static and sets value directly which will be modified by other factors
2486 //this is only basic value and will be overwritten elsewhere !!!
2487 // if (m_unitTarget->isPlayer())
2488 // m_unitTarget->SetFloatValue(PLAYER_DODGE_PERCENTAGE,damage);
2489}

◆ spellEffectDualWield()

void Spell::spellEffectDualWield ( uint8_t  effectIndex)

Definition at line 585 of file SpellEffects.Legacy.cpp.

586{
587 if (m_unitTarget == nullptr)
588 return;
589
591}
void setDualWield(bool enable)
Definition Unit.cpp:3542
Here is the call graph for this function:

◆ spellEffectDualWield2H()

void Spell::spellEffectDualWield2H ( uint8_t  effectIndex)

◆ SpellEffectDualWield2H()

void Spell::SpellEffectDualWield2H ( uint8_t  effectIndex)

Definition at line 6072 of file SpellEffects.Legacy.cpp.

6073{
6074 if (!m_playerTarget)
6075 return;
6076
6078}
void setDualWield2H(bool enable)
Definition Player.cpp:4266
Here is the call graph for this function:

◆ spellEffectDuel()

void Spell::spellEffectDuel ( uint8_t  effectIndex)

◆ SpellEffectDuel()

void Spell::SpellEffectDuel ( uint8_t  effectIndex)

Definition at line 4723 of file SpellEffects.Legacy.cpp.

4724{
4725 if (!p_caster || !p_caster->isAlive())
4726 return;
4727
4728 if (p_caster->isStealthed())
4729 {
4731 return; // Player is stealth
4732 }
4734 return;
4735
4736 /* not implemented yet
4737 \todo dueling zones ? (SPELL_FAILED_NO_DUELING)
4738 if (player->IsInvisible())
4739 {
4740 sendCastResult(SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE);
4741 return;
4742 }
4743 */
4744
4745 //Player* pTarget = sObjHolder.GetObject<Player>(player->getTargetGuid()); // hacky.. and will screw up if plr is deselected..
4746 if (!m_playerTarget)
4747 {
4749 return; // invalid Target
4750 }
4751 if (!m_playerTarget->isAlive())
4752 {
4754 return; // Target not alive
4755 }
4756 // todo
4757 /*if (playerTarget->hasUnitStateFlag(UNIT_STATE_ATTACKING))
4758 {
4759 sendCastResult(SPELL_FAILED_TARGET_IN_COMBAT);
4760 return; // Target in combat with another unit
4761 }*/
4763 {
4765 return; // Already Dueling
4766 }
4767
4769}
void requestDuel(Player *target)
Definition Player.cpp:11875
Here is the call graph for this function:

◆ spellEffectDummy()

void Spell::spellEffectDummy ( uint8_t  effectIndex)

Definition at line 499 of file SpellEffects.Legacy.cpp.

500{
501 // Check that the dummy effect is handled properly in spell script
502 // In case it's not, generate warning to debug log
503 const auto scriptResult = sScriptMgr.callScriptedSpellOnDummyOrScriptedEffect(this, effectIndex);
504 if (scriptResult == SpellScriptCheckDummy::DUMMY_OK)
505 return;
506
507 if (sObjectMgr.checkForDummySpellScripts(static_cast<Player*>(u_caster), m_spellInfo->getId()))
508 return;
509
510 if (sScriptMgr.CallScriptedDummySpell(m_spellInfo->getId(), effectIndex, this))
511 return;
512
513 sLogger.debugFlag(AscEmu::Logging::LF_SPELL_EFF, "Spell::spellEffectDummy : Spell {} ({}) has a dummy effect index (%hhu), but no handler for it.", m_spellInfo->getId(), m_spellInfo->getName(), effectIndex);
514}
Here is the call graph for this function:

◆ spellEffectDummyMelee()

void Spell::spellEffectDummyMelee ( uint8_t  effectIndex)

◆ SpellEffectDummyMelee()

void Spell::SpellEffectDummyMelee ( uint8_t  effectIndex)

Definition at line 5520 of file SpellEffects.Legacy.cpp.

5521{
5522
5523 if (!m_unitTarget || !u_caster)
5524 return;
5525
5526 switch (getSpellInfo()->getId())
5527 {
5528 //SPELL_HASH_OVERPOWER
5529 case 7384:
5530 case 7887:
5531 case 11584:
5532 case 11585:
5533 case 14895:
5534 case 17198:
5535 case 24407:
5536 case 32154:
5537 case 37321:
5538 case 37529:
5539 case 43456:
5540 case 58516:
5541 case 65924:
5542 {
5543 if (p_caster) //warrior : overpower - let us clear the event and the combopoint count
5544 {
5545 p_caster->clearComboPoints(); //some say that we should only remove 1 point per dodge. Due to cooldown you can't cast it twice anyway..
5547 }
5548 } break;
5549
5550 case 20243:
5551 case 30016:
5552 case 30017:
5553 case 30022:
5554 case 36891:
5555 case 36894:
5556 case 38849:
5557 case 38967:
5558 case 44452:
5559 case 47497:
5560 case 47498:
5561 case 57795:
5562 case 60018:
5563 case 62317:
5564 case 69902:
5565 {
5566 //count the number of sunder armors on target
5567 uint32_t sunder_count = 0;
5568 SpellInfo const* spellInfo = nullptr;
5570 {
5571 if (const auto* aur = m_unitTarget->getAuraWithAuraSlot(x))
5572 {
5573 switch (aur->getSpellInfo()->getId())
5574 {
5575 //SPELL_HASH_SUNDER_ARMOR
5576 case 7386:
5577 case 7405:
5578 case 8380:
5579 case 11596:
5580 case 11597:
5581 case 11971:
5582 case 13444:
5583 case 15502:
5584 case 15572:
5585 case 16145:
5586 case 21081:
5587 case 24317:
5588 case 25051:
5589 case 25225:
5590 case 27991:
5591 case 30901:
5592 case 47467:
5593 case 48893:
5594 case 50370:
5595 case 53618:
5596 case 54188:
5597 case 57807:
5598 case 58461:
5599 case 58567:
5600 case 59350:
5601 case 59608:
5602 case 64978:
5603 case 65936:
5604 case 71554:
5605 {
5606 sunder_count++;
5607 spellInfo = aur->getSpellInfo();
5608 } break;
5609 default:
5610 spellInfo = sSpellMgr.getSpellInfo(7386);
5611 break;
5612 }
5613 }
5614 }
5615
5616 if (spellInfo == nullptr)
5617 return; //omg how did this happen ?
5618 //we should also cast sunder armor effect on target with or without dmg
5619 Spell* spell = sSpellMgr.newSpell(u_caster, spellInfo, true, nullptr);
5620 spell->ProcedOnSpell = getSpellInfo();
5621 spell->pSpellId = getSpellInfo()->getId();
5623 spell->prepare(&targets);
5624 if (!sunder_count)
5625 return; //no damage = no joy
5626 damage = damage * sunder_count;
5627 } break;
5628 default:
5629 break;
5630 }
5631
5632 switch (getSpellInfo()->getId())
5633 {
5634 //SPELL_HASH_HEMORRHAGE
5635 case 16511:
5636 case 17347:
5637 case 17348:
5638 case 26864:
5639 case 30478:
5640 case 37331:
5641 case 45897:
5642 case 48660:
5643 case 65954:
5644 {
5645 if (p_caster)
5647 } break;
5648
5649 // AMBUSH
5650 case 8676:
5651 add_damage = 77;
5652 return;
5653 break; // r1
5654 case 8724:
5655 add_damage = 110;
5656 return;
5657 break; // r2
5658 case 8725:
5659 add_damage = 138;
5660 return;
5661 break; // r3
5662 case 11267:
5663 add_damage = 204;
5664 return;
5665 break; // r4
5666 case 11268:
5667 add_damage = 253;
5668 return;
5669 break; // r5
5670 case 11269:
5671 add_damage = 319;
5672 return;
5673 break; // r6
5674 case 27441:
5675 add_damage = 369;
5676 return;
5677 break; // r7
5678 case 48689:
5679 add_damage = 509;
5680 return;
5681 break; // r8
5682 case 48690:
5683 add_damage = 770;
5684 return;
5685 break; // r9
5686 case 48691:
5687 add_damage = 908;
5688 return;
5689 break; // r10
5690
5691 // BACKSTAB
5692 case 53:
5693 add_damage = 15;
5694 return;
5695 break; // r1
5696 case 2589:
5697 add_damage = 30;
5698 return;
5699 break; // r2
5700 case 2590:
5701 add_damage = 48;
5702 return;
5703 break; // r3
5704 case 2591:
5705 add_damage = 69;
5706 return;
5707 break; // r4
5708 case 8721:
5709 add_damage = 90;
5710 return;
5711 break; // r5
5712 case 11279:
5713 add_damage = 135;
5714 return;
5715 break; // r6
5716 case 11280:
5717 add_damage = 165;
5718 return;
5719 break; // r7
5720 case 11281:
5721 add_damage = 210;
5722 return;
5723 break; // r8
5724 case 25300:
5725 add_damage = 225;
5726 return;
5727 break; // r9
5728 case 26863:
5729 add_damage = 255;
5730 return;
5731 break; // r10
5732 case 48656:
5733 add_damage = 383;
5734 return;
5735 break; // r11
5736 case 48657:
5737 add_damage = 465;
5738 return;
5739 break; // r12
5740 }
5741
5742 // rogue ambush etc
5743 for (uint8_t x = 0; x < 3; x++)
5744 if (getSpellInfo()->getEffect(x) == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE)
5745 {
5746 add_damage = damage * (getSpellInfo()->getEffectBasePoints(x) + 1) / 100;
5747 return;
5748 }
5749
5750 //rogue - mutilate ads dmg if target is poisoned
5751 uint32_t pct_dmg_mod = 100;
5752 if (m_unitTarget->isPoisoned())
5753 {
5754 switch (getSpellInfo()->getId())
5755 {
5756 //SPELL_HASH_MUTILATE
5757 case 1329:
5758 case 5374:
5759 case 27576:
5760 case 32319:
5761 case 32320:
5762 case 32321:
5763 case 34411:
5764 case 34412:
5765 case 34413:
5766 case 34414:
5767 case 34415:
5768 case 34416:
5769 case 34417:
5770 case 34418:
5771 case 34419:
5772 case 41103:
5773 case 48661:
5774 case 48662:
5775 case 48663:
5776 case 48664:
5777 case 48665:
5778 case 48666:
5779 case 60850:
5780 pct_dmg_mod = 120;
5781 break;
5782 }
5783 }
5784
5785 WeaponDamageType _type;
5787 _type = RANGED;
5788 else
5789 {
5791 _type = OFFHAND;
5792 else
5793 _type = MELEE;
5794 }
5796 isTargetDamageInfoSet = true;
5797}
@ EVENT_COMBO_POINT_CLEAR_FOR_TARGET
Definition EventMgr.h:81
WeaponDamageType
bool isPoisoned()
Definition Unit.cpp:5762
DamageInfo strike(Unit *pVictim, WeaponDamageType weaponType, SpellInfo const *ability, int32_t add_damage, int32_t pct_dmg_mod, uint32_t exclusive_damage, bool disable_proc, bool skip_hit_check, bool force_crit=false, Spell *castingSpell=nullptr)
Definition Unit.cpp:10407
Here is the call graph for this function:

◆ spellEffectDurabilityDamage()

void Spell::spellEffectDurabilityDamage ( uint8_t  effectIndex)

◆ SpellEffectDurabilityDamage()

void Spell::SpellEffectDurabilityDamage ( uint8_t  effectIndex)

Definition at line 6223 of file SpellEffects.Legacy.cpp.

6224{
6226 return;
6227
6228 int16_t slot = int16_t(getSpellInfo()->getEffectMiscValue(effectIndex));
6229
6230 Item* pItem;
6231 Container* pContainer;
6232 uint32_t j, k;
6233
6234 // FIXME: some spells effects have value -1/-2
6235 // Possibly its mean -1 all player equipped items and -2 all items
6236 if (slot < 0)
6237 {
6238 for (k = 0; k < MAX_INVENTORY_SLOT; k++)
6239 {
6240 pItem = p_caster->getItemInterface()->GetInventoryItem(static_cast<uint16_t>(k));
6241 if (pItem != nullptr)
6242 {
6243 if (pItem->isContainer())
6244 {
6245 pContainer = static_cast< Container* >(pItem);
6246 for (j = 0; j < pContainer->getItemProperties()->ContainerSlots; ++j)
6247 {
6248 pItem = pContainer->getItem(static_cast<uint16_t>(j));
6249 if (pItem != nullptr)
6250 {
6251 uint32_t maxdur = pItem->getMaxDurability();
6252 uint32_t olddur = pItem->getDurability();
6253 uint32_t newdur = (olddur)-(damage);
6254
6255 if (static_cast<int32_t>(newdur) < 0)
6256 newdur = 0;
6257
6258 if (newdur > maxdur)
6259 newdur = maxdur;
6260
6261 pItem->setDurability(newdur);
6262 }
6263 }
6264 }
6265 else
6266 {
6267 uint32_t maxdur = pItem->getMaxDurability();
6268 uint32_t olddur = pItem->getDurability();
6269 uint32_t newdur = (olddur)-(damage);
6270
6271 if (static_cast<int32_t>(newdur) < 0)
6272 newdur = 0;
6273
6274 if (newdur > maxdur)
6275 newdur = maxdur;
6276
6277 // Apply / Disapply enchantements from this item
6278 pItem->setDurability(newdur);
6279 if (newdur == 0 && olddur > 0)
6280 p_caster->applyItemMods(pItem, static_cast<uint16_t>(k), false);
6281 else if (newdur > 0 && olddur == 0)
6282 p_caster->applyItemMods(pItem, static_cast<uint16_t>(k), true);
6283 }
6284 }
6285 }
6286 return;
6287 }
6288
6289 // invalid slot value
6290 if (slot >= INVENTORY_SLOT_BAG_END)
6291 return;
6292
6293 pItem = p_caster->getItemInterface()->GetInventoryItem(slot);
6294 if (pItem)
6295 {
6296 uint32_t maxdur = pItem->getMaxDurability();
6297 uint32_t olddur = pItem->getDurability();
6298 uint32_t newdur = (olddur)-(damage);
6299
6300 if (static_cast<int32_t>(newdur) < 0)
6301 newdur = 0;
6302
6303 if (newdur > maxdur)
6304 newdur = maxdur;
6305
6306 pItem->setDurability(newdur);
6307
6308 // Apply / Disapply enchantements from this item
6309 if (newdur == 0 && olddur > 0)
6310 p_caster->applyItemMods(pItem, slot, false);
6311 else if (newdur > 0 && olddur == 0)
6312 p_caster->applyItemMods(pItem, slot, true);
6313 }
6314}
@ INVENTORY_SLOT_BAG_END
#define MAX_INVENTORY_SLOT
Item * getItem(int16_t slot)
void setDurability(uint32_t durability)
Definition Item.cpp:217
bool isContainer() const
Definition Object.cpp:574
void applyItemMods(Item *item, int16_t slot, bool apply, bool justBrokedown=false, bool skipStatApply=false)
Definition Player.cpp:6972
uint32_t ContainerSlots
Here is the call graph for this function:

◆ spellEffectDurabilityDamagePCT()

void Spell::spellEffectDurabilityDamagePCT ( uint8_t  effectIndex)

◆ SpellEffectDurabilityDamagePCT()

void Spell::SpellEffectDurabilityDamagePCT ( uint8_t  effectIndex)

Definition at line 6316 of file SpellEffects.Legacy.cpp.

6317{
6319 return;
6320
6321 int16_t slot = int16_t(getSpellInfo()->getEffectMiscValue(effectIndex));
6322
6323 Item* pItem;
6324 Container* pContainer;
6325 uint32_t j, k;
6326
6327 // FIXME: some spells effects have value -1/-2
6328 // Possibly its mean -1 all player equipped items and -2 all items
6329 if (slot < 0)
6330 {
6331 for (k = 0; k < MAX_INVENTORY_SLOT; ++k)
6332 {
6333 pItem = p_caster->getItemInterface()->GetInventoryItem(static_cast<uint16_t>(k));
6334 if (pItem != nullptr)
6335 {
6336 if (pItem->isContainer())
6337 {
6338 pContainer = static_cast< Container* >(pItem);
6339 for (j = 0; j < pContainer->getItemProperties()->ContainerSlots; ++j)
6340 {
6341 pItem = pContainer->getItem(static_cast<uint16_t>(j));
6342 if (pItem != nullptr)
6343 {
6344 uint32_t maxdur = pItem->getMaxDurability();
6345 uint32_t olddur = pItem->getDurability();
6346 uint32_t newdur = (olddur - (uint32_t)(maxdur * (damage / 100.0)));
6347
6348 if (static_cast<int32_t>(newdur) < 0)
6349 newdur = 0;
6350
6351 if (newdur > maxdur)
6352 newdur = maxdur;
6353
6354 pItem->setDurability(newdur);
6355 }
6356 }
6357 }
6358 else
6359 {
6360 uint32_t maxdur = pItem->getMaxDurability();
6361 uint32_t olddur = pItem->getDurability();
6362 uint32_t newdur = (olddur - (uint32_t)(maxdur * (damage / 100.0)));
6363
6364 if (static_cast<int32_t>(newdur) < 0)
6365 newdur = 0;
6366
6367 if (newdur > maxdur)
6368 newdur = maxdur;
6369
6370 // Apply / Disapply enchantements from this item
6371 pItem->setDurability(newdur);
6372 if (newdur == 0 && olddur > 0)
6373 p_caster->applyItemMods(pItem, static_cast<uint16_t>(k), false);
6374 else if (newdur > 0 && olddur == 0)
6375 p_caster->applyItemMods(pItem, static_cast<uint16_t>(k), true);
6376 }
6377 }
6378 }
6379 return;
6380 }
6381
6382 // invalid slot value
6383 if (slot >= INVENTORY_SLOT_BAG_END)
6384 return;
6385
6386 if (damage <= 0)
6387 return;
6388
6389 pItem = p_caster->getItemInterface()->GetInventoryItem(slot);
6390 if (pItem)
6391 {
6392 uint32_t maxdur = pItem->getMaxDurability();
6393 uint32_t olddur = pItem->getDurability();
6394 uint32_t newdur = (olddur - (uint32_t)(maxdur * (damage / 100.0)));
6395
6396 if (static_cast<int32_t>(newdur) < 0)
6397 newdur = 0;
6398
6399 if (newdur > maxdur)
6400 newdur = maxdur;
6401
6402 pItem->setDurability(newdur);
6403
6404 // Apply / Disapply enchantements from this item
6405 if (newdur == 0 && olddur > 0)
6406 p_caster->applyItemMods(pItem, slot, false);
6407 else if (newdur > 0 && olddur == 0)
6408 p_caster->applyItemMods(pItem, slot, true);
6409 }
6410}
Here is the call graph for this function:

◆ spellEffectEnchantHeldItem()

void Spell::spellEffectEnchantHeldItem ( uint8_t  effectIndex)

◆ SpellEffectEnchantHeldItem()

void Spell::SpellEffectEnchantHeldItem ( uint8_t  effectIndex)

Definition at line 4850 of file SpellEffects.Legacy.cpp.

4851{
4852 if (!m_playerTarget) return;
4853
4855 if (!item)
4856 return;
4857
4858 uint32_t Duration = 0; // Needs to be found in dbc.. I guess?
4859
4860 switch (getSpellInfo()->getId())
4861 {
4862 //SPELL_HASH_FLAMETONGUE_WEAPON
4863 case 8024:
4864 case 8027:
4865 case 8030:
4866 case 16339:
4867 case 16341:
4868 case 16342:
4869 case 25489:
4870 case 58785:
4871 case 58789:
4872 case 58790:
4873 case 65979:
4874 //SPELL_HASH_WINDFURY_WEAPON
4875 case 8232:
4876 case 8235:
4877 case 10486:
4878 case 16362:
4879 case 25505:
4880 case 32911:
4881 case 35886:
4882 case 58801:
4883 case 58803:
4884 case 58804:
4885 Duration = 10;
4886 break;
4887 default:
4888 Duration = 1800;
4889 break;
4890 }
4891
4892 auto spell_item_enchant = sSpellItemEnchantmentStore.lookupEntry(getSpellInfo()->getEffectMiscValue(effectIndex));
4893
4894 if (!spell_item_enchant)
4895 {
4896 sLogger.failure("Invalid enchantment entry {} for Spell {}", getSpellInfo()->getEffectMiscValue(effectIndex), getSpellInfo()->getId());
4897 return;
4898 }
4899
4901 item->addEnchantment(getSpellInfo()->getEffectMiscValue(effectIndex), TEMP_ENCHANTMENT_SLOT, Duration * 1000);
4902}
@ TEMP_ENCHANTMENT_SLOT
void removeEnchantment(EnchantmentSlot slot, bool timerExpired=false)
Definition Item.cpp:362
bool addEnchantment(uint32_t enchantmentId, EnchantmentSlot slot, uint32_t duration, bool removedAtLogout=false, uint32_t randomSuffix=0)
Definition Item.cpp:286
Here is the call graph for this function:

◆ spellEffectEnchantItem()

void Spell::spellEffectEnchantItem ( uint8_t  effectIndex)

◆ SpellEffectEnchantItem()

void Spell::SpellEffectEnchantItem ( uint8_t  effectIndex)

Definition at line 4073 of file SpellEffects.Legacy.cpp.

4074{
4075 if (!m_itemTarget || !p_caster)
4076 return;
4077
4078 // Vellums
4079 if (getSpellInfo()->getEffectItemType(effectIndex) && (m_itemTarget->getEntry() == 39349 ||
4080 m_itemTarget->getEntry() == 39350 || m_itemTarget->getEntry() == 43146 ||
4081 m_itemTarget->getEntry() == 38682 || m_itemTarget->getEntry() == 37602 ||
4082 m_itemTarget->getEntry() == 43145))
4083 {
4084 uint32_t itemid = getSpellInfo()->getEffectItemType(effectIndex);
4085 ItemProperties const* it = sMySQLStore.getItemProperties(itemid);
4086 if (it == nullptr)
4087 {
4088 p_caster->getSession()->SystemMessage("Item is missing, report this to devs. Entry: %u", itemid);
4089 return;
4090 }
4091
4092 auto pItem = sObjectMgr.createItem(itemid, p_caster);
4093 if (pItem == nullptr)
4094 return;
4095
4097 p_caster->getItemInterface()->AddItemToFreeSlot(std::move(pItem));
4098
4099 return;
4100 }
4101
4102 auto spell_item_enchant = sSpellItemEnchantmentStore.lookupEntry(getSpellInfo()->getEffectMiscValue(effectIndex));
4103
4104 if (!spell_item_enchant)
4105 {
4106 sLogger.failure("Invalid enchantment entry {} for Spell {}", getSpellInfo()->getEffectMiscValue(effectIndex), getSpellInfo()->getId());
4107 return;
4108 }
4109
4111 sGMLog.writefromsession(p_caster->getSession(), "enchanted item for %s", m_itemTarget->getOwner()->getName().c_str());
4112
4113 //remove other perm enchantment that was enchanted by profession
4115 const auto addedEnchantment = m_itemTarget->addEnchantment(getSpellInfo()->getEffectMiscValue(effectIndex), PERM_ENCHANTMENT_SLOT, 0);
4116 if (!addedEnchantment)
4117 return; // Apply failed
4118
4119 if (!i_caster)
4121}
@ PERM_ENCHANTMENT_SLOT
#define sGMLog
uint32_t RemoveItemAmt(uint32_t id, uint32_t amt)
Removes a ammount of items from inventory.
std::tuple< AddItemResult, std::unique_ptr< Item > > AddItemToFreeSlot(std::unique_ptr< Item > item)
Adds a Item to a free slot.
void SystemMessage(const char *format,...)
bool hasPermissions() const
Here is the call graph for this function:

◆ spellEffectEnchantItemPrismatic()

void Spell::spellEffectEnchantItemPrismatic ( uint8_t  effectIndex)

◆ SpellEffectEnchantItemPrismatic()

void Spell::SpellEffectEnchantItemPrismatic ( uint8_t  effectIndex)

Definition at line 6080 of file SpellEffects.Legacy.cpp.

6081{
6082#if VERSION_STRING < WotLK
6083 return;
6084#else
6085 if (!m_itemTarget || !p_caster)
6086 return;
6087
6088 auto spell_item_enchant = sSpellItemEnchantmentStore.lookupEntry(m_spellInfo->getEffectMiscValue(effectIndex));
6089
6090 if (!spell_item_enchant)
6091 {
6092 sLogger.failure("Invalid enchantment entry {} for Spell {}", getSpellInfo()->getEffectMiscValue(effectIndex), getSpellInfo()->getId());
6093 return;
6094 }
6095
6097 sGMLog.writefromsession(p_caster->getSession(), "enchanted item for %s", m_itemTarget->getOwner()->getName().c_str());
6098
6099 //remove other socket enchant
6101 const auto addedEnchantment = m_itemTarget->addEnchantment(m_spellInfo->getEffectMiscValue(effectIndex), PRISMATIC_ENCHANTMENT_SLOT, 0);
6102
6103 if (!addedEnchantment)
6104 return; // Apply failed
6105
6106 m_itemTarget->m_isDirty = true;
6107#endif
6108}
Here is the call graph for this function:

◆ spellEffectEnchantItemTemporary()

void Spell::spellEffectEnchantItemTemporary ( uint8_t  effectIndex)

◆ SpellEffectEnchantItemTemporary()

void Spell::SpellEffectEnchantItemTemporary ( uint8_t  effectIndex)

Definition at line 4123 of file SpellEffects.Legacy.cpp.

4124{
4125 if ((m_itemTarget == nullptr) || (p_caster == nullptr))
4126 return;
4127
4128 uint32_t Duration = m_spellInfo->getEffectBasePoints(effectIndex);
4129 uint32_t EnchantmentID = m_spellInfo->getEffectMiscValue(effectIndex);
4130
4131 // don't allow temporary enchants unless we're the owner of the item
4132 if (m_itemTarget->getOwner() != p_caster)
4133 return;
4134
4135 if (Duration == 0)
4136 {
4137 sLogger.failure("Spell {} ({}) has no enchantment duration. Spell needs to be fixed!", m_spellInfo->getId(), m_spellInfo->getName());
4138 return;
4139 }
4140
4141 if (EnchantmentID == 0)
4142 {
4143 sLogger.failure("Spell {} ({}) has no enchantment ID. Spell needs to be fixed!", m_spellInfo->getId(), m_spellInfo->getName());
4144 return;
4145 }
4146
4147 auto spell_item_enchant = sSpellItemEnchantmentStore.lookupEntry(EnchantmentID);
4148 if (spell_item_enchant == nullptr)
4149 {
4150 sLogger.failure("Invalid enchantment entry {} for Spell {}", EnchantmentID, getSpellInfo()->getId());
4151 return;
4152 }
4153
4155
4156 const auto addedEnchantment = m_itemTarget->addEnchantment(EnchantmentID, TEMP_ENCHANTMENT_SLOT, Duration * 1000);
4157 if (!addedEnchantment)
4158 return; // Apply failed
4159
4160 auto skill_line_ability = sSpellMgr.getFirstSkillEntryForSpell(getSpellInfo()->getId());
4161 if (skill_line_ability != nullptr)
4162 DetermineSkillUp(static_cast<uint16_t>(skill_line_ability->skilline), m_itemTarget->getItemProperties()->ItemLevel);
4163}
Here is the call graph for this function:

◆ spellEffectEnergize()

void Spell::spellEffectEnergize ( uint8_t  effectIndex)

◆ SpellEffectEnergize()

void Spell::SpellEffectEnergize ( uint8_t  effectIndex)

Definition at line 3199 of file SpellEffects.Legacy.cpp.

3200{
3201 if (!m_unitTarget || !m_unitTarget->isAlive())
3202 return;
3203
3204 uint32_t modEnergy = 0;
3205 switch (getSpellInfo()->getId())
3206 {
3207 case 30824: // Shamanistic Rage
3208 modEnergy = damage * getUnitTarget()->getCalculatedAttackPower() / 100;
3209 break;
3210 case 31786: // Paladin - Spiritual Attunement
3211 if (ProcedOnSpell)
3212 {
3213 SpellInfo const* motherspell = sSpellMgr.getSpellInfo(pSpellId);
3214 if (motherspell)
3215 {
3216 //heal amount from procspell (we only proceed on a heal spell)
3217 uint32_t healamt = 0;
3219 healamt = ProcedOnSpell->calculateEffectValue(0);
3221 healamt = ProcedOnSpell->calculateEffectValue(1);
3223 healamt = ProcedOnSpell->calculateEffectValue(2);
3224 modEnergy = (motherspell->calculateEffectValue(0)) * (healamt) / 100;
3225 }
3226 }
3227 break;
3228 case 57669:
3229 {
3230 modEnergy = Util::float2int32(0.01f * m_unitTarget->getBaseMana());
3231 }
3232 break;
3233 case 31930:
3234 {
3235 if (u_caster)
3236 modEnergy = Util::float2int32(0.25f * m_unitTarget->getBaseMana());
3237 }
3238 break;
3239 case 2687: // Improved Bloodrage, dirty fix
3240 {
3241 modEnergy = damage;
3242 if (p_caster)
3243 {
3244 if (p_caster->hasSpell(12818))
3245 modEnergy += 110; //60
3246 if (p_caster->hasSpell(12301))
3247 modEnergy += 60; //30
3248 }
3249 }
3250 break;
3251 default:
3252 modEnergy = damage;
3253 break;
3254 }
3255
3256 if (m_unitTarget->hasAurasWithId(17619))
3257 modEnergy = uint32_t(modEnergy * 1.4f);
3258
3259 if (u_caster)
3260 u_caster->energize(m_unitTarget, getSpellInfo()->getId(), modEnergy, static_cast<PowerType>(getSpellInfo()->getEffectMiscValue(effectIndex)));
3261}
Here is the call graph for this function:

◆ spellEffectEnvironmentalDamage()

void Spell::spellEffectEnvironmentalDamage ( uint8_t  effectIndex)

◆ SpellEffectEnvironmentalDamage()

void Spell::SpellEffectEnvironmentalDamage ( uint8_t  effectIndex)

Definition at line 1966 of file SpellEffects.Legacy.cpp.

1967{
1968 if (!m_playerTarget) return;
1969
1970 if (m_playerTarget->m_schoolImmunityList[getSpellInfo()->getFirstSchoolFromSchoolMask()])
1971 {
1973 return;
1974 }
1975 //this is GO, not unit
1976 m_targetDamageInfo = m_caster->doSpellDamage(m_playerTarget, getSpellInfo()->getId(), static_cast<float_t>(damage), effectIndex, m_triggeredSpell, false, false, isForcedCrit, this);
1977 isTargetDamageInfoSet = true;
1978
1980}
@ DAMAGE_FIRE
DamageInfo doSpellDamage(Unit *victim, uint32_t spellId, float_t damage, uint8_t effIndex, bool isTriggered=false, bool isPeriodic=false, bool isLeech=false, bool forceCrit=false, Spell *spell=nullptr, Aura *aur=nullptr, AuraEffectModifier *aurEff=nullptr)
Definition Object.cpp:771
void sendEnvironmentalDamageLogPacket(uint64_t guid, uint8_t type, uint32_t damage, uint64_t unk=0)
Definition Unit.cpp:6935
Here is the call graph for this function:

◆ spellEffectFeedPet()

void Spell::spellEffectFeedPet ( uint8_t  effectIndex)

◆ SpellEffectFeedPet()

void Spell::SpellEffectFeedPet ( uint8_t  effectIndex)

Cast feed pet effect

  • effect is item level and pet level dependent, aura ticks are 35, 17, 8 (*1000) happiness

Definition at line 5132 of file SpellEffects.Legacy.cpp.

5133{
5134 // food flags and food level are checked in Spell::CanCast()
5135 if (!m_itemTarget || !p_caster)
5136 return;
5137
5138 Pet* pPet = p_caster->getPet();
5139 if (!pPet)
5140 return;
5141
5142 /** Cast feed pet effect
5143 - effect is item level and pet level dependent, aura ticks are 35, 17, 8 (*1000) happiness*/
5144 int8_t deltaLvl = static_cast<int8_t>(pPet->getLevel() - m_itemTarget->getItemProperties()->ItemLevel);
5145 damage /= 1000; //damage of Feed pet spell is 35000
5146 if (deltaLvl > 10) damage = damage >> 1;//divide by 2
5147 if (deltaLvl > 20) damage = damage >> 1;
5148 damage *= 1000;
5149
5150 const auto spellInfo = sSpellMgr.getSpellInfo(getSpellInfo()->getEffectTriggerSpell(effectIndex));
5151 Spell* sp = sSpellMgr.newSpell(p_caster, spellInfo, true, nullptr);
5152 sp->forced_basepoints->set(0, damage);
5153 SpellCastTargets tgt(pPet->getGuid());
5154 sp->prepare(&tgt);
5155
5156 if (m_itemTarget->getStackCount() > 1)
5157 {
5159 m_itemTarget->m_isDirty = true;
5160 }
5161 else
5162 {
5164 m_itemTarget = nullptr;
5165 }
5166}
uint32_t getStackCount() const
Definition Item.cpp:143
uint32_t getEffectTriggerSpell(uint8_t idx) const
Here is the call graph for this function:

◆ spellEffectForceCast()

void Spell::spellEffectForceCast ( uint8_t  effectIndex)

Definition at line 680 of file SpellEffects.Legacy.cpp.

681{
682 if (m_unitTarget == nullptr || getUnitCaster() == nullptr)
683 return;
684
685 const auto triggerInfo = sSpellMgr.getSpellInfo(getSpellInfo()->getEffectTriggerSpell(effectIndex));
686 if (triggerInfo == nullptr)
687 return;
688
689 // TODO: figure the logic here, sometimes target should be original caster and sometimes effect target
690 // hackfixing for now -Appled
691 Unit* target = nullptr;
692 switch (getSpellInfo()->getId())
693 {
694 case 72378: // Deathbringer Saurfang - Blood Nova 10m
695 case 73058: // Deathbringer Saurfang - Blood Nova 25m
696 target = m_unitTarget;
697 break;
698 default:
699 target = getUnitCaster();
700 break;
701 }
702
703 // TODO: original caster can also be gameobject
704 m_unitTarget->castSpell(target, triggerInfo, true);
705}
Here is the call graph for this function:

◆ SpellEffectForceDeselect()

void Spell::SpellEffectForceDeselect ( uint8_t  effectIndex)

Definition at line 6433 of file SpellEffects.Legacy.cpp.

6434{
6435 //clear focus SMSG_BREAK_TARGET
6436
6437 //clear target
6439
6440 //stop attacking and pet target
6441}
Here is the call graph for this function:

◆ spellEffectForgetSpecialization()

void Spell::spellEffectForgetSpecialization ( uint8_t  effectIndex)

◆ SpellEffectForgetSpecialization()

void Spell::SpellEffectForgetSpecialization ( uint8_t  effectIndex)

Definition at line 5980 of file SpellEffects.Legacy.cpp.

5981{
5982 if (!m_playerTarget) return;
5983
5984 uint32_t spellid = getSpellInfo()->getEffectTriggerSpell(effectIndex);
5985 m_playerTarget->removeSpell(spellid, false);
5986
5987 sLogger.debugFlag(AscEmu::Logging::LF_SPELL_EFF, "Player {} have forgot spell {} from spell {} (caster: {})", m_playerTarget->getGuidLow(), spellid, getSpellInfo()->getId(), m_caster->getGuidLow());
5988}
uint32_t getGuidLow() const
Definition Object.cpp:304
bool removeSpell(uint32_t spellId, bool moveToDeleted)
Definition Player.cpp:3945
Here is the call graph for this function:

◆ spellEffectHeal()

void Spell::spellEffectHeal ( uint8_t  effectIndex)

◆ SpellEffectHeal()

void Spell::SpellEffectHeal ( uint8_t  effectIndex)

Definition at line 2005 of file SpellEffects.Legacy.cpp.

2006{
2007 if (p_caster != nullptr)
2008 {
2009 // HACKY but with SM_FEffect2_bonus it doesnt work
2010 uint32_t fireResistanceAura[] =
2011 {
2012 //SPELL_HASH_FIRE_RESISTANCE_AURA
2013 19891,
2014 19899,
2015 19900,
2016 27153,
2017 48947,
2018 0
2019 };
2020
2021 uint32_t frostResistanceAura[] =
2022 {
2023 //SPELL_HASH_FROST_RESISTANCE_AURA
2024 19888,
2025 19897,
2026 19898,
2027 27152,
2028 48945,
2029 0
2030 };
2031
2032 uint32_t shadowResistanceAura[] =
2033 {
2034 //SPELL_HASH_SHADOW_RESISTANCE_AURA
2035 19876,
2036 19895,
2037 19896,
2038 27151,
2039 48943,
2040 0
2041 };
2042
2043 uint32_t retributionAura[] =
2044 {
2045 //SPELL_HASH_RETRIBUTION_AURA
2046 7294,
2047 8990,
2048 10298,
2049 10299,
2050 10300,
2051 10301,
2052 13008,
2053 27150,
2054 54043,
2055 0
2056 };
2057
2058 uint32_t devotionAura[] =
2059 {
2060 //SPELL_HASH_DEVOTION_AURA
2061 465,
2062 643,
2063 1032,
2064 8258,
2065 10290,
2066 10291,
2067 10292,
2068 10293,
2069 17232,
2070 27149,
2071 41452,
2072 48941,
2073 48942,
2074 52442,
2075 57740,
2076 58944,
2077 0
2078 };
2079
2080 // Apply this only on targets, which have one of paladins auras
2081 if (m_unitTarget && (m_unitTarget->hasAurasWithId(devotionAura) || m_unitTarget->hasAurasWithId(retributionAura) ||
2082 m_unitTarget->hasAurasWithId(19746) || m_unitTarget->hasAurasWithId(32223) || m_unitTarget->hasAurasWithId(fireResistanceAura) ||
2083 m_unitTarget->hasAurasWithId(frostResistanceAura) || m_unitTarget->hasAurasWithId(shadowResistanceAura)))
2084 {
2085 if (p_caster->hasSpell(20140)) // Improved Devotion Aura Rank 3
2086 damage = (int32_t)(damage * 1.06);
2087 else if (p_caster->hasSpell(20139)) // Improved Devotion Aura Rank 2
2088 damage = (int32_t)(damage * 1.04);
2089 else if (p_caster->hasSpell(20138)) // Improved Devotion Aura Rank 1
2090 damage = (int32_t)(damage * 1.02);
2091 }
2092
2093 if (p_caster->hasSpell(54943) && p_caster->hasAurasWithId(20165)) // Glyph of Seal of Light
2094 damage = (int32_t)(damage * 1.05);
2095 }
2096
2097 auto heal = damage;
2098
2099 if (getSpellInfo()->getEffectChainTarget(effectIndex)) //chain
2100 {
2101 if (!chaindamage)
2102 {
2103 chaindamage = heal;
2105 isTargetDamageInfoSet = true;
2106 }
2107 else
2108 {
2109 int32_t reduce = getSpellInfo()->getEffectDieSides(effectIndex) + 1;
2110 if (u_caster != nullptr)
2111 {
2113 }
2114 chaindamage -= (reduce * chaindamage) / 100;
2116 isTargetDamageInfoSet = true;
2117 }
2118 }
2119 else
2120 {
2121 //yep, the usual special case. This one is shaman talent : Nature's guardian
2122 //health is below 30%, we have a mother spell to get value from
2123 switch (getSpellInfo()->getId())
2124 {
2125 case 31616:
2126 {
2128 {
2129 //check for that 10 second cooldown
2130 const auto spellInfo = sSpellMgr.getSpellInfo(pSpellId);
2131 if (spellInfo)
2132 {
2133 //heal value is received by the level of current active talent :s
2134 //maybe we should use CalculateEffect(uint32_t i) to gain SM benefits
2135 int32_t value = 0;
2136 int32_t basePoints = spellInfo->getEffectBasePoints(effectIndex) + 1; //+(m_caster->getLevel()*basePointsPerLevel);
2137 uint32_t randomPoints = spellInfo->getEffectDieSides(effectIndex);
2138 if (randomPoints <= 1)
2139 value = basePoints;
2140 else
2141 value = basePoints + Util::getRandomUInt(randomPoints);
2142 //the value is in percent. Until now it's a fixed 10%
2143 const auto amt = m_unitTarget->getMaxHealth()*value / 100.0f;
2145 isTargetDamageInfoSet = true;
2146 }
2147 }
2148 }
2149 break;
2150 //Bloodthirst
2151 case 23880:
2152 {
2153 if (m_unitTarget)
2154 {
2156 isTargetDamageInfoSet = true;
2157 }
2158 }
2159 break;
2160 case 22845: // Druid: Frenzied Regeneration
2161 {
2162 if (m_unitTarget == nullptr || !m_unitTarget->isPlayer() || !m_unitTarget->isAlive())
2163 break;
2164
2165 Player* mPlayer = static_cast< Player* >(m_unitTarget);
2166 if (!mPlayer->isInFeralForm() ||
2167 (mPlayer->getShapeShiftForm() != FORM_BEAR &&
2168 mPlayer->getShapeShiftForm() != FORM_DIREBEAR))
2169 break;
2170 uint32_t val = mPlayer->getPower(POWER_TYPE_RAGE);
2171 if (val > 100)
2172 val = 100;
2173 uint32_t HpPerPoint = Util::float2int32((mPlayer->getMaxHealth() * 0.003f)); //0.3% of hp per point of rage
2174 uint32_t healAmt = HpPerPoint * (val / 10); //1 point of rage = 0.3% of max hp
2175 mPlayer->modPower(POWER_TYPE_RAGE, -1 * val);
2176
2177 if (val)
2178 mPlayer->addSimpleHealingBatchEvent(healAmt, mPlayer, sSpellMgr.getSpellInfo(22845));
2179 }
2180 break;
2181 case 18562: //druid - swiftmend
2182 {
2183 if (m_unitTarget)
2184 {
2185 float_t new_dmg = 0.0f;
2186 //consume rejuvenetaion and regrowth
2187
2188 uint32_t regrowth[] =
2189 {
2190 //SPELL_HASH_REGROWTH
2191 8936,
2192 8938,
2193 8939,
2194 8940,
2195 8941,
2196 9750,
2197 9856,
2198 9857,
2199 9858,
2200 16561,
2201 20665,
2202 22373,
2203 22695,
2204 26980,
2205 27637,
2206 28744,
2207 34361,
2208 39000,
2209 39125,
2210 48442,
2211 48443,
2212 66067,
2213 67968,
2214 67969,
2215 67970,
2216 69882,
2217 71141,
2218 0
2219 };
2220 Aura* taura = m_unitTarget->getAuraWithId(regrowth); //Regrowth
2221 if (taura && taura->getSpellInfo())
2222 {
2223 uint32_t amplitude = taura->getSpellInfo()->getEffectAmplitude(1) / 1000;
2224 if (!amplitude)
2225 amplitude = 3;
2226
2227 //our hapiness is that we did not store the aura mod amount so we have to recalc it
2228 Spell* spell = sSpellMgr.newSpell(m_caster, taura->getSpellInfo(), false, nullptr);
2229 uint32_t healamount = spell->calculateEffect(1);
2230 delete spell;
2231 spell = nullptr;
2232 new_dmg = healamount * 18.0f / amplitude;
2233
2234 taura->removeAura();
2235
2236 //do not remove flag if we still can cast it again
2237 uint32_t rejuvenation[] =
2238 {
2239 //SPELL_HASH_REJUVENATION
2240 774,
2241 1058,
2242 1430,
2243 2090,
2244 2091,
2245 3627,
2246 8070,
2247 8910,
2248 9839,
2249 9840,
2250 9841,
2251 12160,
2252 15981,
2253 20664,
2254 20701,
2255 25299,
2256 26981,
2257 26982,
2258 27532,
2259 28716,
2260 28722,
2261 28723,
2262 28724,
2263 31782,
2264 32131,
2265 38657,
2266 42544,
2267 48440,
2268 48441,
2269 53607,
2270 64801,
2271 66065,
2272 67971,
2273 67972,
2274 67973,
2275 69898,
2276 70691,
2277 71142,
2278 0
2279 };
2280
2281 if (!m_unitTarget->hasAurasWithId(rejuvenation))
2282 {
2285 }
2286 }
2287 else
2288 {
2289 uint32_t rejuvenation[] =
2290 {
2291 //SPELL_HASH_REJUVENATION
2292 774,
2293 1058,
2294 1430,
2295 2090,
2296 2091,
2297 3627,
2298 8070,
2299 8910,
2300 9839,
2301 9840,
2302 9841,
2303 12160,
2304 15981,
2305 20664,
2306 20701,
2307 25299,
2308 26981,
2309 26982,
2310 27532,
2311 28716,
2312 28722,
2313 28723,
2314 28724,
2315 31782,
2316 32131,
2317 38657,
2318 42544,
2319 48440,
2320 48441,
2321 53607,
2322 64801,
2323 66065,
2324 67971,
2325 67972,
2326 67973,
2327 69898,
2328 70691,
2329 71142,
2330 0
2331 };
2332
2333 taura = m_unitTarget->getAuraWithId(rejuvenation); //Rejuvenation
2334 if (taura && taura->getSpellInfo())
2335 {
2336 uint32_t amplitude = taura->getSpellInfo()->getEffectAmplitude(0) / 1000;
2337 if (!amplitude) amplitude = 3;
2338
2339 //our happiness is that we did not store the aura mod amount so we have to recalc it
2340 Spell* spell = sSpellMgr.newSpell(m_caster, taura->getSpellInfo(), false, nullptr);
2341 uint32_t healamount = spell->calculateEffect(0);
2342 delete spell;
2343 spell = nullptr;
2344 new_dmg = healamount * 12.0f / amplitude;
2345
2346 taura->removeAura();
2347
2350 }
2351 }
2352
2353 if (new_dmg > 0.0f)
2354 {
2355 const auto spellInfo = sSpellMgr.getSpellInfo(18562);
2356 Spell* spell = sSpellMgr.newSpell(m_unitTarget, spellInfo, true, nullptr);
2358 m_targetDamageInfo = m_caster->doSpellHealing(m_unitTarget, spellInfo->getId(), new_dmg, m_triggeredSpell, false, false, isForcedCrit, this);
2359 isTargetDamageInfoSet = true;
2360 delete spell;
2361 }
2362 }
2363 }
2364 break;
2365 default:
2366 m_targetDamageInfo = m_caster->doSpellHealing(m_unitTarget, getSpellInfo()->getId(), static_cast<float_t>(heal), m_triggeredSpell, false, false, isForcedCrit, this);
2367 isTargetDamageInfoSet = true;
2368 break;
2369 }
2370 }
2371}
@ AURASTATE_FLAG_SWIFTMEND
@ EVENT_REJUVENATION_FLAG_EXPIRE
yeah, there are more then 1 flags
Definition EventMgr.h:69
@ SPELLMOD_JUMP_REDUCE
DamageInfo doSpellHealing(Unit *victim, uint32_t spellId, float_t heal, bool isTriggered=false, bool isPeriodic=false, bool isLeech=false, bool forceCrit=false, Spell *spell=nullptr, Aura *aur=nullptr, AuraEffectModifier *aurEff=nullptr)
Definition Object.cpp:1132
bool isInFeralForm()
Definition Player.cpp:4113
uint32_t getEffectAmplitude(uint8_t idx) const
void setUnitTarget(Unit *_unit)
Definition Spell.cpp:5681
void addSimpleHealingBatchEvent(uint32_t heal, Unit *healer=nullptr, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:7395
uint32_t getMaxHealth() const
Definition Unit.cpp:625
Here is the call graph for this function:

◆ spellEffectHealMaxHealth()

void Spell::spellEffectHealMaxHealth ( uint8_t  effectIndex)

◆ SpellEffectHealMaxHealth()

void Spell::SpellEffectHealMaxHealth ( uint8_t  effectIndex)

Definition at line 4428 of file SpellEffects.Legacy.cpp.

4429{
4430 if (!m_unitTarget || !m_unitTarget->isAlive())
4431 return;
4432
4434 if (!dif)
4435 {
4437 return;
4438 }
4439
4441
4442 if (u_caster != nullptr)
4443 {
4444 switch (this->getSpellInfo()->getId())
4445 {
4446 //SPELL_HASH_LAY_ON_HANDS
4447 case 633:
4448 case 2800:
4449 case 9257:
4450 case 10310:
4451 case 17233:
4452 case 20233:
4453 case 20236:
4454 case 27154:
4455 case 48788:
4456 case 53778:
4457 u_caster->castSpell(m_unitTarget, 25771, true);
4458 break;
4459 default:
4460 break;
4461 }
4462 }
4463}
Here is the call graph for this function:

◆ spellEffectHealMechanical()

void Spell::spellEffectHealMechanical ( uint8_t  effectIndex)

◆ SpellEffectHealMechanical()

void Spell::SpellEffectHealMechanical ( uint8_t  effectIndex)

Definition at line 4643 of file SpellEffects.Legacy.cpp.

4644{
4646 return;
4647
4648 m_targetDamageInfo = m_caster->doSpellHealing(m_unitTarget, getSpellInfo()->getId(), static_cast<float_t>(damage), m_triggeredSpell, false, false, isForcedCrit, this);
4649 isTargetDamageInfoSet = true;
4650}
@ UNIT_TYPE_MECHANICAL
Here is the call graph for this function:

◆ spellEffectHealthLeech()

void Spell::spellEffectHealthLeech ( uint8_t  effectIndex)

Definition at line 516 of file SpellEffects.Legacy.cpp.

517{
518 if (m_unitTarget == nullptr || !m_unitTarget->isAlive())
519 return;
520
521 m_targetDamageInfo = m_caster->doSpellDamage(m_unitTarget, getSpellInfo()->getId(), static_cast<float_t>(damage), effIndex, m_triggeredSpell, false, true, isForcedCrit, this);
523}
Here is the call graph for this function:

◆ spellEffectInebriate()

void Spell::spellEffectInebriate ( uint8_t  effectIndex)

◆ SpellEffectInebriate()

void Spell::SpellEffectInebriate ( uint8_t  effectIndex)

Definition at line 5117 of file SpellEffects.Legacy.cpp.

5118{
5119 if (m_playerTarget == nullptr)
5120 return;
5121
5122 // Drunkee!
5124 uint16_t drunkMod = static_cast<uint16_t>(damage)* 256;
5125 if (currentDrunk + drunkMod > 0xFFFF)
5126 currentDrunk = 0xFFFF;
5127 else
5128 currentDrunk += drunkMod;
5130}
void setServersideDrunkValue(uint16_t newDrunkValue, uint32_t itemId=0)
Definition Player.cpp:11829
uint16_t getServersideDrunkValue() const
Definition Player.cpp:11827
Here is the call graph for this function:

◆ spellEffectInstantKill()

void Spell::spellEffectInstantKill ( uint8_t  effectIndex)

◆ SpellEffectInstantKill()

void Spell::SpellEffectInstantKill ( uint8_t  effectIndex)

Definition at line 765 of file SpellEffects.Legacy.cpp.

766{
768 return;
769
770 //Sacrifice: if spell caster has "void walker" pet, pet dies and spell caster gets a
771 /*Sacrifices the Voidwalker, giving its owner a shield that will absorb
772 305 damage for 30 sec. While the shield holds, spellcasting will not be \
773 interrupted by damage.*/
774
775 /*
776 Demonic Sacrifice
777
778 When activated, sacrifices your summoned demon to grant you an effect that lasts
779 30 minutes. The effect is canceled if any Demon is summoned.
780 Imp: Increases your Fire damage by 15%.
781 Voidwalker: Restores 3% of total Health every 4 sec.
782 Succubus: Increases your Shadow damage by 15%.
783 Felhunter: Restores 2% of total Mana every 4 sec.
784
785 When activated, sacrifices your summoned demon to grant you an effect that lasts $18789d. The effect is canceled if any Demon is summoned.
786
787 Imp: Increases your Fire damage by $18789s1%.
788
789 Voidwalker: Restores $18790s1% of total Health every $18790t1 sec.
790
791 Succubus: Increases your Shadow damage by $18791s1%.
792
793 Felhunter: Restores $18792s1% of total Mana every $18792t1 sec.
794
795 */
796 uint32_t spellId = getSpellInfo()->getId();
797
798 switch (spellId)
799 {
800 case 48743:
801 {
802 // retarget? some one test this spell.
803 return;
804 }
805 break;
806 case 18788: //Demonic Sacrifice (508745)
807 {
808 uint32_t DemonicSacEffectSpellId = 0;
809 switch (m_unitTarget->getEntry())
810 {
811 case 416:
812 DemonicSacEffectSpellId = 18789;
813 break; //Imp
814 case 417:
815 DemonicSacEffectSpellId = 18792;
816 break; //Felhunter
817 case 1860:
818 DemonicSacEffectSpellId = 18790;
819 break; //VoidWalker
820 case 1863:
821 DemonicSacEffectSpellId = 18791;
822 break; //Succubus
823 case 17252:
824 DemonicSacEffectSpellId = 35701;
825 break; //felguard
826 }
827 if (DemonicSacEffectSpellId)
828 {
829 SpellInfo const* se = sSpellMgr.getSpellInfo(DemonicSacEffectSpellId);
830 if (se && u_caster)
831 u_caster->castSpell(u_caster, se, true);
832 }
833 } break;
834
835 //SPELL_HASH_SACRIFICE
836 case 1050:
837 case 7812:
838 case 7885:
839 case 19438:
840 case 19439:
841 case 19440:
842 case 19441:
843 case 19442:
844 case 19443:
845 case 19444:
846 case 19445:
847 case 19446:
848 case 19447:
849 case 20381:
850 case 20382:
851 case 20383:
852 case 20384:
853 case 20385:
854 case 20386:
855 case 22651:
856 case 27273:
857 case 27492:
858 case 30115:
859 case 33587:
860 case 34661:
861 case 47985:
862 case 47986:
863 case 48001:
864 case 48002:
865 {
866 if (!u_caster || !u_caster->isPet())
867 return;
868
869 //TO< Pet* >(u_caster)->Dismiss(true);
870
871 SpellInfo const* se = sSpellMgr.getSpellInfo(5);
872 if (static_cast< Pet* >(u_caster)->getUnitOwner() == nullptr)
873 return;
874
876 Spell* sp = sSpellMgr.newSpell(static_cast< Pet* >(u_caster)->getUnitOwner(), se, true, nullptr);
877 sp->prepare(&targets);
878 return;
879 } break;
880
881 }
882
883 //SPELL_HASH_DEMONIC_SACRIFICE
884 if (getSpellInfo()->getId() == 18788)
885 {
886 if (!p_caster || !m_unitTarget || !m_unitTarget->isPet())
887 return;
888
889 //TO< Pet* >(m_unitTarget)->Dismiss(true);
890
891 SpellInfo const* se = sSpellMgr.getSpellInfo(5);
892
894 Spell* sp = sSpellMgr.newSpell(p_caster, se, true, nullptr);
895 sp->prepare(&targets);
896 return;
897 }
898 else
899 {
900 // moar cheaters
901 if (!p_caster || (u_caster && u_caster->isPet()))
902 return;
903
905 return;
906 }
907
908 //instant kill effects don't have a log
909 //m_caster->SpellNonMeleeDamageLog(m_unitTarget, GetProto()->getId(), m_unitTarget->getHealth(), true);
910 // cebernic: the value of instant kill must be higher than normal health,cuz anti health regenerated.
911 if (u_caster != nullptr)
913 else
915}
void dealDamage(Unit *victim, uint32_t damage, uint32_t spellId, bool removeAuras=true)
Definition Unit.cpp:7089
Here is the call graph for this function:

◆ spellEffectInterruptCast()

void Spell::spellEffectInterruptCast ( uint8_t  effectIndex)

◆ SpellEffectInterruptCast()

void Spell::SpellEffectInterruptCast ( uint8_t  effectIndex)

Definition at line 4465 of file SpellEffects.Legacy.cpp.

4466{
4467 if (!m_unitTarget || !m_unitTarget->isAlive())
4468 return;
4469
4470 if (getSpellInfo()->getAttributesExG() & ATTRIBUTESEXG_INTERRUPT_NPC && m_unitTarget->isPlayer())
4471 return;
4472
4473 // Get target's current spell (either channeled or generic spell with cast time)
4474 if (m_unitTarget->isCastingSpell(false, true))
4475 {
4476 Spell* TargetSpell = nullptr;
4478 {
4480 }
4481 // No need to check cast time for generic spells, checked already in Object::isCastingSpell()
4483 {
4485 }
4486
4487 if (TargetSpell != nullptr)
4488 {
4489 uint32_t school = TargetSpell->getSpellInfo()->getFirstSchoolFromSchoolMask(); // Get target's casting spell school
4490 int32_t duration = getDuration(); // Duration of school lockout
4491
4492 // Check for CastingTime (to prevent interrupting instant casts), PreventionType
4493 // and InterruptFlags of target's casting spell
4494 if (school
4495 && (TargetSpell->getState() == SPELL_STATE_CHANNELING
4496 || (TargetSpell->getState() == SPELL_STATE_CASTING && TargetSpell->getSpellInfo()->getCastingTimeIndex() > 0))
4500 {
4501 if (m_unitTarget->isPlayer())
4502 {
4503 // Check for interruption reducing talents
4505 if (DurationModifier >= -100)
4506 duration = (duration * (100 + DurationModifier)) / 100;
4507
4508 // Prevent player from casting in that school
4509 static_cast<Player*>(m_unitTarget)->sendPreventSchoolCast(school, duration);
4510 }
4511 else
4512 {
4513 // Prevent unit from casting in that school
4514 m_unitTarget->m_schoolCastPrevent[school] = duration + Util::getMSTime();
4515 }
4516
4517 // Interrupt the spell cast
4518 m_unitTarget->interruptSpell(TargetSpell->getSpellInfo()->getId(), false);
4519 }
4520 }
4521 }
4522}
@ CHANNEL_INTERRUPT_ON_MOVEMENT
@ CURRENT_CHANNELED_SPELL
Definition Object.hpp:68
@ CURRENT_GENERIC_SPELL
Definition Object.hpp:67
@ ATTRIBUTESEXG_INTERRUPT_NPC
uint32_t getInterruptFlags() const
uint32_t getCastingTimeIndex() const
int32_t getCastTimeLeft() const
Definition Spell.cpp:5545
uint32_t m_schoolCastPrevent[TOTAL_SPELL_SCHOOLS]
Definition Unit.hpp:1362
int32_t m_mechanicDurationPctMod[28]
Definition Unit.hpp:1365
Here is the call graph for this function:

◆ spellEffectJumpBehindTarget()

void Spell::spellEffectJumpBehindTarget ( uint8_t  effectIndex)

◆ SpellEffectJumpBehindTarget()

void Spell::SpellEffectJumpBehindTarget ( uint8_t  effectIndex)

Definition at line 3029 of file Spell.Legacy.cpp.

3030{
3031 if (u_caster == nullptr)
3032 return;
3033
3035 return;
3036
3038 {
3040
3041 if (uobj == nullptr || !uobj->isCreatureOrPlayer())
3042 return;
3043 Unit* un = static_cast<Unit*>(uobj);
3044 float rad = un->getBoundingRadius() + u_caster->getBoundingRadius();
3045 float angle = float(un->GetOrientation() + M_PI); //behind
3046 float x = un->GetPositionX() + cosf(angle) * rad;
3047 float y = un->GetPositionY() + sinf(angle) * rad;
3048 float z = un->GetPositionZ();
3049 float o = un->calcRadAngle(x, y, un->GetPositionX(), un->GetPositionY());
3050
3051 float speedXY, speedZ;
3052 calculateJumpSpeeds(u_caster, getSpellInfo() ,effectIndex, u_caster->getExactDist2d(un->GetPositionX(), un->GetPositionY()), speedXY, speedZ);
3053 u_caster->getMovementManager()->moveJump(x, y, z, o, speedXY, speedZ, EVENT_JUMP, !m_targets.getUnitTargetGuid());
3054 }
3055}
@ EVENT_JUMP
void moveJump(LocationVector const &pos, float speedXY, float speedZ, uint32_t id=EVENT_JUMP, bool hasOrientation=false)
float getExactDist2d(const float x, const float y) const
Definition Object.hpp:411
void calculateJumpSpeeds(Unit *unitCaster, SpellInfo const *spellInfo, uint8_t i, float dist, float &speedXY, float &speedZ)
float getBoundingRadius() const
Definition Unit.cpp:1246
Here is the call graph for this function:

◆ spellEffectJumpTarget()

void Spell::spellEffectJumpTarget ( uint8_t  effectIndex)

◆ SpellEffectJumpTarget()

void Spell::SpellEffectJumpTarget ( uint8_t  effectIndex)

Definition at line 2926 of file Spell.Legacy.cpp.

2927{
2928 if (u_caster == nullptr)
2929 return;
2930
2931#ifdef FT_VEHICLES
2932 if (u_caster->getVehicleKit() || u_caster->isTrainingDummy())
2933 return;
2934#else
2936 return;
2937#endif
2938
2939 float x = 0;
2940 float y = 0;
2941 float z = 0;
2942 float o = 0;
2943
2945 {
2947
2948 if (uobj == nullptr || !uobj->isCreatureOrPlayer())
2949 {
2950 return;
2951 }
2952
2954
2957
2958 if (dx == 0.0f || dy == 0.0f)
2959 {
2960 return;
2961 }
2962
2963 float alpha = atanf(dy / dx);
2964 if (dx < 0)
2965 {
2966 alpha += M_PI_FLOAT;
2967 }
2968
2969 x = rad * cosf(alpha) + m_unitTarget->GetPositionX();
2970 y = rad * sinf(alpha) + m_unitTarget->GetPositionY();
2972 }
2973 else
2974 {
2975 //this can also jump to a point
2976 if (m_targets.hasSource())
2977 {
2978 auto source = m_targets.getSource();
2979 x = source.x;
2980 y = source.y;
2981 z = source.z;
2982 }
2984 {
2985 auto destination = m_targets.getDestination();
2986 x = destination.x;
2987 y = destination.y;
2988 z = destination.z;
2989 }
2990 }
2991
2992 float speedZ = 0.0f;
2993 float speedXY = 0.0f;
2994
2996 calculateJumpSpeeds(u_caster, getSpellInfo() ,effectIndex, u_caster->getExactDist2d(x, y), speedXY, speedZ);
2997 u_caster->getMovementManager()->moveJump(x, y, z, o, speedXY, speedZ);
2998}
virtual bool isTrainingDummy()
Definition Unit.hpp:1079
Here is the call graph for this function:

◆ spellEffectKillCredit()

void Spell::spellEffectKillCredit ( uint8_t  effectIndex)

◆ SpellEffectKillCredit()

void Spell::SpellEffectKillCredit ( uint8_t  effectIndex)

Definition at line 5990 of file SpellEffects.Legacy.cpp.

5991{
5992 CreatureProperties const* ci = sMySQLStore.getCreatureProperties(getSpellInfo()->getEffectMiscValue(effectIndex));
5993 if (m_playerTarget != nullptr && ci != nullptr)
5994 sQuestMgr._OnPlayerKill(m_playerTarget, getSpellInfo()->getEffectMiscValue(effectIndex), false);
5995}
Here is the call graph for this function:

◆ spellEffectKnockBack()

void Spell::spellEffectKnockBack ( uint8_t  effectIndex)

◆ SpellEffectKnockBack()

void Spell::SpellEffectKnockBack ( uint8_t  effectIndex)

Definition at line 4999 of file SpellEffects.Legacy.cpp.

5000{
5001 if (m_unitTarget == nullptr || !m_unitTarget->isAlive())
5002 return;
5003
5004 // Spells with SPELL_EFFECT_KNOCK_BACK (like Thunderstorm) can't knockback target if target has ROOT/STUN
5006 return;
5007
5008 float ratio = 0.1f;
5009 float speedxy = float(m_spellInfo->getEffectMiscValue(effectIndex)) * ratio;
5010 float speedz = float(damage) * ratio;
5011 if (speedxy < 0.01f && speedz < 0.01f)
5012 return;
5013
5014 float x, y;
5015#if VERSION_STRING >= TBC
5017 {
5019 {
5020 auto destination = m_targets.getDestination();
5021 x = destination.x;
5022 y = destination.y;
5023 }
5024 else
5025 return;
5026 }
5027 else
5028#endif
5029 {
5030 m_caster->getPosition(x, y);
5031 }
5032
5033 m_unitTarget->knockbackFrom(x, y, speedxy, speedz);
5034}
@ UNIT_STATE_ROOTED
void getPosition(float &x, float &y) const
Definition Object.hpp:370
void knockbackFrom(float x, float y, float speedXY, float speedZ)
Definition Unit.cpp:7636
Here is the call graph for this function:

◆ spellEffectKnockBack2()

void Spell::spellEffectKnockBack2 ( uint8_t  effectIndex)

◆ SpellEffectKnockBack2()

void Spell::SpellEffectKnockBack2 ( uint8_t  effectIndex)

Definition at line 5036 of file SpellEffects.Legacy.cpp.

5037{
5038 if (m_unitTarget == nullptr || !m_unitTarget->isAlive())
5039 return;
5040
5041 m_unitTarget->handleKnockback(m_caster, getSpellInfo()->getEffectMiscValue(effectIndex) / 10.0f, damage / 10.0f);
5042}
virtual void handleKnockback(Object *caster, float horizontal, float vertical)
Definition Unit.cpp:3331
Here is the call graph for this function:

◆ spellEffectLeap()

void Spell::spellEffectLeap ( uint8_t  effectIndex)

◆ SpellEffectLeap()

void Spell::SpellEffectLeap ( uint8_t  effectIndex)

Definition at line 3164 of file SpellEffects.Legacy.cpp.

3165{
3166 if (m_unitTarget == nullptr)
3167 return;
3168
3169 float radius = getEffectRadius(effectIndex);
3171
3173 dtNavMesh* nav = const_cast<dtNavMesh*>(mmap->GetNavMesh(m_caster->GetMapId()));
3174 // dtNavMeshQuery* nav_query = const_cast<dtNavMeshQuery*>(mmap->GetNavMeshQuery(m_caster->GetMapId(), m_caster->GetInstanceID()));
3175 //NavMeshData* nav = CollideInterface.GetNavMesh(m_caster->GetMapId());
3176
3177 if (nav != nullptr)
3178 {
3179 float destx, desty, destz;
3180 m_unitTarget->GetPoint(m_unitTarget->GetOrientation(), radius, destx, desty, destz);
3181 if (m_playerTarget != nullptr)
3183 else
3184 {
3185 float speedXY, speedZ;
3187 u_caster->getMovementManager()->moveJump(destx, desty, destz, m_unitTarget->GetOrientation(), speedXY, speedZ, EVENT_JUMP, !m_unitTarget);
3188 }
3189 }
3190 else
3191 {
3192 if (m_playerTarget == nullptr) //let client handle this for players
3193 return;
3194
3196 }
3197}
@ AURA_INTERRUPT_ON_ANY_DAMAGE_TAKEN
static MMapManager * createOrGetMMapManager()
dtNavMesh const * GetNavMesh(uint32_t mapId)
bool GetPoint(float angle, float rad, float &outx, float &outy, float &outz, bool sloppypath=false)
Definition Object.cpp:4661
bool safeTeleport(uint32_t mapId, uint32_t instanceId, const LocationVector &vec)
Definition Player.cpp:1772
Here is the call graph for this function:

◆ spellEffectLearnPetSpell()

void Spell::spellEffectLearnPetSpell ( uint8_t  effectIndex)

◆ SpellEffectLearnPetSpell()

void Spell::SpellEffectLearnPetSpell ( uint8_t  effectIndex)

Definition at line 4263 of file SpellEffects.Legacy.cpp.

4264{
4265 /*if (m_unitTarget && m_caster->getObjectTypeId() == TYPEID_PLAYER)
4266 {
4267 if (m_unitTarget->isPet() && m_unitTarget->getObjectTypeId() == TYPEID_UNIT)
4268 {
4269 TO< Player* >(m_caster)->AddPetSpell(GetProto()->EffectTriggerSpell[i], m_unitTarget->getEntry());
4270 }
4271 }*/
4272
4274 {
4275 Pet* pPet = static_cast< Pet* >(m_unitTarget);
4276 if (!pPet->isHunterPet())
4278
4279 pPet->addSpell(sSpellMgr.getSpellInfo(getSpellInfo()->getEffectTriggerSpell(effectIndex)));
4280
4281 // Send Packet
4282 /* WorldPacket data(SMSG_SET_EXTRA_AURA_INFO_OBSOLETE, 22);
4283 data << pPet->getGuid() << uint8_t(0) << uint32_t(GetProto()->EffectTriggerSpell[i]) << uint32_t(-1) << uint32_t(0);
4284 p_caster->getSession()->sendPacket(&data);*/
4285 }
4286}
bool isHunterPet() const
Definition Pet.cpp:485
void addSpell(SpellInfo const *spellInfo, bool silently=false)
Definition Pet.cpp:1008
void addSummonSpell(uint32_t entry, uint32_t spellId)
Definition Player.cpp:13969
Here is the call graph for this function:
Here is the caller graph for this function:

◆ spellEffectLearnSpec()

void Spell::spellEffectLearnSpec ( uint8_t  effectIndex)

◆ SpellEffectLearnSpec()

void Spell::SpellEffectLearnSpec ( uint8_t  effectIndex)

Definition at line 6181 of file SpellEffects.Legacy.cpp.

6182{
6183 if (p_caster == nullptr)
6184 return;
6185
6187 p_caster->smsg_TalentsInfo(false);
6188}
void smsg_TalentsInfo(bool SendPetTalents)
Definition Player.cpp:6152
uint8_t m_talentSpecsCount
Definition Player.hpp:1987
Here is the call graph for this function:

◆ spellEffectLearnSpell()

void Spell::spellEffectLearnSpell ( uint8_t  effectIndex)

◆ SpellEffectLearnSpell()

void Spell::SpellEffectLearnSpell ( uint8_t  effectIndex)

Definition at line 3660 of file SpellEffects.Legacy.cpp.

3661{
3662 if (m_playerTarget == nullptr && m_unitTarget && m_unitTarget->isPet()) // something's wrong with this logic here.
3663 {
3664 // bug in target map fill?
3665 //playerTarget = m_caster->getWorldMap()->GetPlayer((uint32_t)m_targets.getUnitTarget());
3666 SpellEffectLearnPetSpell(effectIndex);
3667 return;
3668 }
3669
3670 if (getSpellInfo()->getId() == 483 || getSpellInfo()->getId() == 55884) // "Learning"
3671 {
3672 if (!p_caster) return;
3673
3674 uint32_t spellid = damage;
3675 if (!spellid || !sSpellMgr.getSpellInfo(spellid)) return;
3676
3677 // learn me!
3678 p_caster->addSpell(spellid);
3679
3680 // no normal handler
3681 return;
3682 }
3683
3684 if (m_playerTarget)
3685 {
3686 /*if (u_caster && playerTarget->isHostileTo(u_caster))
3687 return;*/
3688
3689 uint32_t spellToLearn = getSpellInfo()->getEffectTriggerSpell(effectIndex);
3690 m_playerTarget->addSpell(spellToLearn);
3691
3692 if (spellToLearn == 2575) //hacky fix for mining from creatures
3693 m_playerTarget->addSpell(32606);
3694
3695 if (spellToLearn == 2366) //hacky fix for herbalism from creatures
3696 m_playerTarget->addSpell(32605);
3697
3698 //smth is wrong here, first we add this spell to player then we may cast it on player...
3699 SpellInfo const* spellinfo = sSpellMgr.getSpellInfo(spellToLearn);
3700 //remove specializations
3701 switch (spellinfo->getId())
3702 {
3703 case 26801: //Shadoweave Tailoring
3704 m_playerTarget->removeSpell(26798, false); //Mooncloth Tailoring
3705 m_playerTarget->removeSpell(26797, false); //Spellfire Tailoring
3706 break;
3707 case 26798: // Mooncloth Tailoring
3708 m_playerTarget->removeSpell(26801, false); //Shadoweave Tailoring
3709 m_playerTarget->removeSpell(26797, false); //Spellfire Tailoring
3710 break;
3711 case 26797: //Spellfire Tailoring
3712 m_playerTarget->removeSpell(26801, false); //Shadoweave Tailoring
3713 m_playerTarget->removeSpell(26798, false); //Mooncloth Tailoring
3714 break;
3715 case 10656: //Dragonscale Leatherworking
3716 m_playerTarget->removeSpell(10658, false); //Elemental Leatherworking
3717 m_playerTarget->removeSpell(10660, false); //Tribal Leatherworking
3718 break;
3719 case 10658: //Elemental Leatherworking
3720 m_playerTarget->removeSpell(10656, false); //Dragonscale Leatherworking
3721 m_playerTarget->removeSpell(10660, false); //Tribal Leatherworking
3722 break;
3723 case 10660: //Tribal Leatherworking
3724 m_playerTarget->removeSpell(10656, false); //Dragonscale Leatherworking
3725 m_playerTarget->removeSpell(10658, false); //Elemental Leatherworking
3726 break;
3727 case 28677: //Elixir Master
3728 m_playerTarget->removeSpell(28675, false); //Potion Master
3729 m_playerTarget->removeSpell(28672, false); //Transmutation Maste
3730 break;
3731 case 28675: //Potion Master
3732 m_playerTarget->removeSpell(28677, false); //Elixir Master
3733 m_playerTarget->removeSpell(28672, false); //Transmutation Maste
3734 break;
3735 case 28672: //Transmutation Master
3736 m_playerTarget->removeSpell(28675, false); //Potion Master
3737 m_playerTarget->removeSpell(28677, false); //Elixir Master
3738 break;
3739 case 20219: //Gnomish Engineer
3740 m_playerTarget->removeSpell(20222, false); //Goblin Engineer
3741 break;
3742 case 20222: //Goblin Engineer
3743 m_playerTarget->removeSpell(20219, false); //Gnomish Engineer
3744 break;
3745 case 9788: //Armorsmith
3746 m_playerTarget->removeSpell(9787, false); //Weaponsmith
3747 m_playerTarget->removeSpell(17039, false); //Master Swordsmith
3748 m_playerTarget->removeSpell(17040, false); //Master Hammersmith
3749 m_playerTarget->removeSpell(17041, false); //Master Axesmith
3750 break;
3751 case 9787: //Weaponsmith
3752 m_playerTarget->removeSpell(9788, false); //Armorsmith
3753 break;
3754 case 17041: //Master Axesmith
3755 m_playerTarget->removeSpell(9788, false); //Armorsmith
3756 m_playerTarget->removeSpell(17040, false); //Master Hammersmith
3757 m_playerTarget->removeSpell(17039, false); //Master Swordsmith
3758 break;
3759 case 17040: //Master Hammersmith
3760 m_playerTarget->removeSpell(9788, false); //Armorsmith
3761 m_playerTarget->removeSpell(17039, false); //Master Swordsmith
3762 m_playerTarget->removeSpell(17041, false); //Master Axesmith
3763 break;
3764 case 17039: //Master Swordsmith
3765 m_playerTarget->removeSpell(9788, false); //Armorsmith
3766 m_playerTarget->removeSpell(17040, false); //Master Hammersmith
3767 m_playerTarget->removeSpell(17041, false); //Master Axesmith
3768 break;
3769 }
3770 for (uint8_t j = 0; j < 3; j++)
3771 if (spellinfo->getEffect(j) == SPELL_EFFECT_WEAPON ||
3772 spellinfo->getEffect(j) == SPELL_EFFECT_PROFICIENCY ||
3773 spellinfo->getEffect(j) == SPELL_EFFECT_DUAL_WIELD)
3774 {
3775 Spell* sp = sSpellMgr.newSpell(m_unitTarget, spellinfo, true, nullptr);
3777 sp->prepare(&targets);
3778 break;
3779 }
3780 return;
3781 }
3782
3783 // if we got here... try via pet spells..
3784 SpellEffectLearnPetSpell(effectIndex);
3785}
@ SPELL_EFFECT_DUAL_WIELD
void SpellEffectLearnPetSpell(uint8_t effectIndex)
Here is the call graph for this function:

◆ spellEffectMilling()

void Spell::spellEffectMilling ( uint8_t  effectIndex)

◆ SpellEffectMilling()

void Spell::SpellEffectMilling ( uint8_t  effectIndex)

Definition at line 6130 of file SpellEffects.Legacy.cpp.

6131{
6132 if (!p_caster) return;
6133
6134 if (!m_itemTarget) // this should never happen
6135 {
6137 return;
6138 }
6139
6140 //Fill Prospecting loot
6142 if (!m_itemTarget->m_loot)
6143 {
6144 m_itemTarget->m_loot = std::make_unique<Loot>();
6145 sLootMgr.fillItemLoot(p_caster, m_itemTarget->m_loot.get(), m_itemTarget->getEntry(), 0);
6146 }
6147
6148 if (m_itemTarget->m_loot->items.size() > 0)
6149 {
6150 sLogger.debugFlag(AscEmu::Logging::LF_SPELL_EFF, "Successfully milled item {}", uint32_t(m_itemTarget->getEntry()));
6152 }
6153 else // this should never happen either
6154 {
6155 sLogger.debugFlag(AscEmu::Logging::LF_SPELL_EFF, "Milling failed, item {} has no loot", uint32_t(m_itemTarget->getEntry()));
6157 }
6158}
@ LOOT_MILLING
Here is the call graph for this function:

◆ spellEffectNotImplemented()

void Spell::spellEffectNotImplemented ( uint8_t  effectIndex)

Definition at line 489 of file SpellEffects.Legacy.cpp.

490{
491 sLogger.debugFlag(AscEmu::Logging::LF_SPELL_EFF, "Spells: Unhandled spell effect {} in spell {}.", getSpellInfo()->getEffect(effIndex), getSpellInfo()->getId());
492}
Here is the call graph for this function:

◆ spellEffectNotUsed()

void Spell::spellEffectNotUsed ( uint8_t  effectIndex)

Definition at line 494 of file SpellEffects.Legacy.cpp.

495{
496 // Handled elsewhere or not used, so do nothing
497}

◆ spellEffectOpenLock()

void Spell::spellEffectOpenLock ( uint8_t  effectIndex)

◆ SpellEffectOpenLock()

void Spell::SpellEffectOpenLock ( uint8_t  effectIndex)

Definition at line 3393 of file SpellEffects.Legacy.cpp.

3394{
3395 if (!p_caster)
3396 return;
3397
3398 uint8_t loottype = 0;
3399
3400 uint32_t locktype = getSpellInfo()->getEffectMiscValue(effectIndex);
3401 switch (locktype)
3402 {
3403#if VERSION_STRING <= WotLK
3404 case LOCKTYPE_PICKLOCK:
3405 {
3406 uint32_t v = 0;
3408
3409 if (m_itemTarget)
3410 {
3412 return;
3413
3414 auto lock = sLockStore.lookupEntry(m_itemTarget->getItemProperties()->LockId);
3415 if (!lock)
3416 return;
3417
3418 for (uint8_t j = 0; j < LOCK_NUM_CASES; ++j)
3419 {
3420 if (lock->locktype[j] == 2 && lock->minlockskill[j] && lockskill >= lock->minlockskill[j])
3421 {
3422 v = lock->minlockskill[j];
3423 m_itemTarget->m_isLocked = false;
3426 break;
3427 }
3428 }
3429 }
3430 else if (m_gameObjTarget)
3431 {
3432 auto gameobject_info = m_gameObjTarget->GetGameObjectProperties();
3433 if (m_gameObjTarget->getState() == 0)
3434 return;
3435
3436 auto lock = sLockStore.lookupEntry(gameobject_info->raw.parameter_0);
3437 if (lock == nullptr)
3438 return;
3439
3440 for (uint8_t j = 0; j < LOCK_NUM_CASES; ++j)
3441 {
3442 if (lock->locktype[j] == 2 && lock->minlockskill[j] && lockskill >= lock->minlockskill[j])
3443 {
3444 v = lock->minlockskill[j];
3447 //Add Fill GO loot here
3449 {
3451 if (pLGO->loot.items.size() == 0)
3452 {
3453 if (m_gameObjTarget->getWorldMap() != nullptr)
3455 else
3457
3458 DetermineSkillUp(SKILL_LOCKPICKING, v / 5); //to prevent free skill up
3459 }
3460 }
3461 loottype = LOOT_CORPSE;
3462 //End of it
3463 break;
3464 }
3465 }
3466 }
3467 }
3468 break;
3469#endif
3470 case LOCKTYPE_HERBALISM:
3471 {
3472 if (!m_gameObjTarget) return;
3473
3475 bool bAlreadyUsed = false;
3476
3477 if (static_cast<Player*>(m_caster)->getSkillLineCurrent(SKILL_HERBALISM) < v)
3478 {
3479 //sendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
3480 return;
3481 }
3482 else
3483 {
3485 {
3487
3488 if (pLGO->loot.items.size() == 0)
3489 {
3490 if (m_gameObjTarget->getWorldMap() != nullptr)
3492 else
3494 }
3495 else
3496 {
3497 bAlreadyUsed = true;
3498 }
3499 }
3500 }
3501 loottype = LOOT_SKINNING;
3502
3503 //Skill up
3504 if (!bAlreadyUsed) //Avoid cheats with opening/closing without taking the loot
3506 }
3507 break;
3508 case LOCKTYPE_MINING:
3509 {
3510 if (!m_gameObjTarget)
3511 return;
3512
3514 bool bAlreadyUsed = false;
3515
3516 if (static_cast<Player*>(m_caster)->getSkillLineCurrent(SKILL_MINING) < v)
3517 {
3518 //sendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
3519 return;
3520 }
3521 else if (m_gameObjTarget->IsLootable())
3522 {
3524 if (pLGO->loot.items.size() == 0)
3525 {
3526 if (m_gameObjTarget->getWorldMap() != nullptr)
3528 else
3530 }
3531 }
3532 else
3533 {
3534 bAlreadyUsed = true;
3535 }
3536 loottype = LOOT_SKINNING;
3537
3538 //Skill up
3539 if (!bAlreadyUsed) //Avoid cheats with opening/closing without taking the loot
3541 }
3542 break;
3543 case LOCKTYPE_SLOW_OPEN: // used for BG go's
3544 {
3545 if (!m_gameObjTarget) return;
3548 return;
3549
3551 SpellInfo const* en = sSpellMgr.getSpellInfo(spellid);
3552 Spell* sp = sSpellMgr.newSpell(p_caster, en, true, nullptr);
3553 SpellCastTargets tgt;
3555 sp->prepare(&tgt);
3556 return;
3557 }
3558 break;
3560 {
3561 if (m_gameObjTarget == nullptr)
3562 return;
3563
3565 }
3566 break;
3567
3569 if (m_gameObjTarget == nullptr)
3570 return;
3571
3572 if ((p_caster != nullptr) && (p_caster->getBattleground() != nullptr))
3574
3575 // there is no break here on purpose
3576
3577 default://not profession
3578 {
3579 if (m_gameObjTarget == nullptr)
3580 return;
3581
3584
3587
3590
3591 if (sQuestMgr.OnActivateQuestGiver(m_gameObjTarget, p_caster))
3592 return;
3593
3594 if (sQuestMgr.OnGameObjectActivate(p_caster, m_gameObjTarget))
3595 {
3597 return;
3598 }
3599
3601 {
3603
3604 if (pLGO->loot.items.size() == 0)
3605 {
3606 if (m_gameObjTarget->getWorldMap() != nullptr)
3608 else
3610 }
3611 }
3612 loottype = LOOT_CORPSE;
3613 }
3614 break;
3615 };
3617 static_cast< Player* >(m_caster)->sendLoot(m_gameObjTarget->getGuid(), loottype, m_gameObjTarget->GetMapId());
3618}
@ GO_FLAG_NONE
@ ITEM_FLAG_LOOTABLE
@ LOCKTYPE_QUICK_OPEN
Definition LockTypes.hpp:19
@ LOCKTYPE_SLOW_OPEN
Definition LockTypes.hpp:26
@ LOCKTYPE_QUICK_CLOSE
Definition LockTypes.hpp:20
@ GO_STATE_CLOSED
@ LOOT_CORPSE
@ LOOT_SKINNING
virtual bool HookQuickLockOpen(GameObject *go, Player *player, Spell *spell)
virtual bool HookSlowLockOpen(GameObject *pGo, Player *pPlayer, Spell *pSpell)
virtual bool IsLootable()
Definition GameObject.h:203
uint8_t getGoType() const
virtual void Use(uint64_t)
Definition GameObject.h:205
void setState(uint8_t state)
uint32_t GetGOReqSkill()
void setFlags(uint32_t flags)
virtual void onUse(Player *)
uint8_t getState() const
virtual void OnGameObjectActivate(GameObject *, Player *)
void addFlags(uint32_t flags)
Definition Item.cpp:189
Player * ToPlayer()
Definition Object.hpp:391
void updateNearbyQuestGameObjects()
Definition Player.cpp:9043
void setGameObjectTarget(uint64_t guid)
InstanceScript * getScript()
std::vector< LootItem > items
Definition Loot.hpp:39
Here is the call graph for this function:

◆ spellEffectOpenLockItem()

void Spell::spellEffectOpenLockItem ( uint8_t  effectIndex)

◆ SpellEffectOpenLockItem()

void Spell::SpellEffectOpenLockItem ( uint8_t  effectIndex)

Definition at line 4329 of file SpellEffects.Legacy.cpp.

4330{
4331 if (p_caster == nullptr || i_caster == nullptr)
4332 return;
4333
4335}
void handleSpellLoot(uint32_t itemId)
Definition Player.cpp:13255
Here is the call graph for this function:

◆ spellEffectParry()

void Spell::spellEffectParry ( uint8_t  effectIndex)

◆ SpellEffectParry()

void Spell::SpellEffectParry ( uint8_t  effectIndex)

Definition at line 2491 of file SpellEffects.Legacy.cpp.

2492{
2493 if (m_unitTarget)
2495}
void setcanparry(bool newstatus)
Definition Unit.hpp:1434
Here is the call graph for this function:

◆ spellEffectPersistentAA()

void Spell::spellEffectPersistentAA ( uint8_t  effectIndex)

◆ SpellEffectPersistentAA()

void Spell::SpellEffectPersistentAA ( uint8_t  effectIndex)

Definition at line 2738 of file SpellEffects.Legacy.cpp.

2739{
2740 if (m_AreaAura || !m_caster->IsInWorld())
2741 return;
2742 //create only 1 dyn object
2743 uint32_t dur = getDuration();
2744 float r = getEffectRadius(effectIndex);
2745
2746 //Note: this code seems to be useless
2747 //this must be only source point or dest point
2748 //this AREA aura it's applied on area
2749 //it can'be on unit or self or item or object
2750 //uncomment it if I'm wrong
2751 //We are thinking in general so it might be useful later DK
2752
2753 // grep: this is a hack!
2754 // our shitty dynobj system doesn't support GO casters, so we gotta
2755 // kinda have 2 summoners for traps that apply AA.
2757
2758 if (g_caster != nullptr && g_caster->getUnitOwner() && !m_unitTarget)
2759 {
2760 Unit* caster = g_caster->getUnitOwner();
2761 dynObj->create(caster, this, g_caster->GetPosition(), dur, r, DYNAMIC_OBJECT_AREA_SPELL);
2762 m_AreaAura = true;
2763 return;
2764 }
2765
2766 switch (m_targets.getTargetMask())
2767 {
2768 case TARGET_FLAG_SELF:
2769 {
2770 dynObj->create(u_caster, this, m_caster->GetPosition(), dur, r, DYNAMIC_OBJECT_AREA_SPELL);
2771 }
2772 break;
2773 case TARGET_FLAG_UNIT:
2774 {
2775 if (!m_unitTarget || !m_unitTarget->isAlive())
2776 {
2777 dynObj->remove();
2778 return;
2779 }
2780
2782 }
2783 break;
2784 case TARGET_FLAG_OBJECT:
2785 {
2786 if (!m_unitTarget || !m_unitTarget->isAlive())
2787 {
2788 dynObj->remove();
2789 return;
2790 }
2791
2793 }
2794 break;
2796 {
2797 auto source = m_targets.getSource();
2798 dynObj->create(u_caster, this, source, dur, r, DYNAMIC_OBJECT_AREA_SPELL);
2799 }
2800 break;
2802 {
2803 auto destination = m_targets.getDestination();
2804 if (u_caster != nullptr)
2805 dynObj->create(u_caster, this, destination, dur, r, DYNAMIC_OBJECT_AREA_SPELL);
2806 else if (g_caster != nullptr)
2807 dynObj->create(g_caster->getUnitOwner(), this, destination, dur, r, DYNAMIC_OBJECT_AREA_SPELL);
2808 }
2809 break;
2810 default:
2811 dynObj->remove();
2812 return;
2813 }
2814
2815 if (u_caster)
2816 if (getSpellInfo()->getChannelInterruptFlags() > 0)
2817 {
2820 }
2821
2822 m_AreaAura = true;
2823}
@ DYNAMIC_OBJECT_AREA_SPELL
Here is the call graph for this function:

◆ spellEffectPickpocket()

void Spell::spellEffectPickpocket ( uint8_t  effectIndex)

◆ SpellEffectPickpocket()

void Spell::SpellEffectPickpocket ( uint8_t  effectIndex)

Definition at line 4549 of file SpellEffects.Legacy.cpp.

4550{
4551 //Show random loot based on roll,
4553 return;
4554
4555 Creature* target = static_cast< Creature* >(m_unitTarget);
4556 if (target->IsPickPocketed() || (target->GetCreatureProperties()->Type != UNIT_TYPE_HUMANOID))
4557 {
4559 return;
4560 }
4561
4562 sLootMgr.fillPickpocketingLoot(p_caster, &m_unitTarget->loot, m_unitTarget->getEntry(), 0);
4563
4564 uint32_t _rank = static_cast< Creature* >(m_unitTarget)->GetCreatureProperties()->Rank;
4566
4568 target->SetPickPocketed(true);
4569}
@ LOOT_PICKPOCKETING
@ RATE_MONEY
Definition WorldConfig.h:29
void SetPickPocketed(bool val=true)
bool IsPickPocketed()
uint32_t gold
Definition Loot.hpp:42
Here is the call graph for this function:

◆ spellEffectPlayerPull()

void Spell::spellEffectPlayerPull ( uint8_t  effectIndex)

◆ SpellEffectPlayerPull()

void Spell::SpellEffectPlayerPull ( uint8_t  effectIndex)

Definition at line 5810 of file SpellEffects.Legacy.cpp.

5811{
5813 return;
5814
5815 Player* p_target = static_cast< Player* >(m_unitTarget);
5816
5817 // calculate destination
5818 float pullD = p_target->CalcDistance(m_caster) - p_target->getBoundingRadius() - (u_caster ? u_caster->getBoundingRadius() : 0) - 1.0f;
5819 float pullO = p_target->calcRadAngle(p_target->GetPositionX(), p_target->GetPositionY(), m_caster->GetPositionX(), m_caster->GetPositionY());
5820 float pullX = p_target->GetPositionX() + pullD * cosf(pullO);
5821 float pullY = p_target->GetPositionY() + pullD * sinf(pullO);
5822 float pullZ = m_caster->GetPositionZ() + 0.3f;
5823 uint32_t time = uint32_t(pullD * 42.0f);
5824
5825 p_target->SetOrientation(pullO);
5826
5828 data << p_target->GetNewGUID();
5829 data << uint8_t(0);
5830 data << p_target->GetPositionX();
5831 data << p_target->GetPositionY();
5832 data << p_target->GetPositionZ();
5833 data << Util::getMSTime();
5834 data << uint8_t(4);
5835 data << pullO;
5836 data << uint32_t(0x00001000);
5837 data << time;
5838 data << uint32_t(1);
5839 data << pullX;
5840 data << pullY;
5841 data << pullZ;
5842
5843 p_target->sendMessageToSet(&data, true);
5844}
void SetOrientation(float o)
Definition Object.hpp:358
void sendMessageToSet(WorldPacket *data, bool sendToSelf, bool sendToOwnTeam=false) override
Definition Player.cpp:3192
Here is the call graph for this function:
Here is the caller graph for this function:

◆ spellEffectPlayMusic()

void Spell::spellEffectPlayMusic ( uint8_t  effectIndex)

◆ SpellEffectPlayMusic()

void Spell::SpellEffectPlayMusic ( uint8_t  effectIndex)

Definition at line 5967 of file SpellEffects.Legacy.cpp.

5968{
5969 uint32_t soundid = m_spellInfo->getEffectMiscValue(effectIndex);
5970
5971 if (soundid == 0)
5972 {
5973 sLogger.failure("Spell {} ({}) has no sound ID to play. Spell needs fixing!", m_spellInfo->getId(), m_spellInfo->getName());
5974 return;
5975 }
5976
5977 m_caster->PlaySoundToSet(soundid);
5978}
void PlaySoundToSet(uint32_t sound_entry)
Definition Object.cpp:4407
Here is the call graph for this function:

◆ spellEffectPowerBurn()

void Spell::spellEffectPowerBurn ( uint8_t  effectIndex)

◆ SpellEffectPowerBurn()

void Spell::SpellEffectPowerBurn ( uint8_t  effectIndex)

Definition at line 4351 of file SpellEffects.Legacy.cpp.

4352{
4354 return;
4355
4356 if (m_unitTarget->isPlayer())
4357 {
4358 Player* mPlayer = static_cast< Player* >(m_unitTarget);
4359 if (mPlayer->isInFeralForm())
4360 return;
4361
4362 // Resilience - reduces the effect of mana drains by (CalcRating*2)%.
4363 damage = Util::float2int32(damage * (1 - ((static_cast< Player* >(m_unitTarget)->calcRating(CR_CRIT_TAKEN_SPELL) * 2) / 100.0f)));
4364 }
4365 int32_t mult = damage;
4367 if (m_caster->isCreatureOrPlayer()) //Spell ctor has ASSERT(m_caster != NULL) so there's no need to add NULL checks, even if static analysis reports them.
4368 {
4369 Unit* caster = static_cast< Unit* >(m_caster);
4370 if ((uint32_t)damage > caster->getMaxPower(POWER_TYPE_MANA) * (mult * 2) / 100)
4371 damage = caster->getMaxPower(POWER_TYPE_MANA) * (mult * 2) / 100;
4372 }
4373
4375
4377
4378 m_targetDamageInfo = m_caster->doSpellDamage(m_unitTarget, getSpellInfo()->getId(), mana * getSpellInfo()->getEffectMultipleValue(effectIndex), effectIndex, m_triggeredSpell, false, false, isForcedCrit, this);
4379 isTargetDamageInfoSet = true;
4380}
@ CR_CRIT_TAKEN_SPELL
PowerType getPowerType() const
Definition Unit.cpp:462
Here is the call graph for this function:

◆ spellEffectPowerDrain()

void Spell::spellEffectPowerDrain ( uint8_t  effectIndex)

◆ SpellEffectPowerDrain()

void Spell::SpellEffectPowerDrain ( uint8_t  effectIndex)

Definition at line 1982 of file SpellEffects.Legacy.cpp.

1983{
1984 if (!m_unitTarget || !m_unitTarget->isAlive())
1985 return;
1986
1987 auto powerField = static_cast<PowerType>(getSpellInfo()->getEffectMiscValue(effectIndex));
1988 auto curPower = m_unitTarget->getPower(powerField);
1989 if (powerField == POWER_TYPE_MANA && m_unitTarget->isPlayer())
1990 {
1991 Player* mPlayer = static_cast< Player* >(m_unitTarget);
1992 if (mPlayer->isInFeralForm())
1993 return;
1994
1995 // Resilience - reduces the effect of mana drains by (CalcRating*2)%.
1996 damage = Util::float2int32(damage * (1 - ((static_cast< Player* >(m_unitTarget)->calcRating(CR_CRIT_TAKEN_SPELL) * 2) / 100.0f)));
1997 }
1998 uint32_t amt = damage + ((u_caster->GetDamageDoneMod(getSpellInfo()->getFirstSchoolFromSchoolMask()) * 80) / 100);
1999 if (amt > curPower)
2000 amt = curPower;
2001 m_unitTarget->setPower(powerField, curPower - amt);
2002 u_caster->energize(u_caster, getSpellInfo()->getId(), amt, powerField);
2003}
virtual int32_t GetDamageDoneMod(uint16_t)
Definition Unit.hpp:1367
Here is the call graph for this function:

◆ spellEffectPowerFunnel()

void Spell::spellEffectPowerFunnel ( uint8_t  effectIndex)

◆ SpellEffectPowerFunnel()

void Spell::SpellEffectPowerFunnel ( uint8_t  effectIndex)

Definition at line 4420 of file SpellEffects.Legacy.cpp.

4421{
4423 return;
4424
4425 //does not exist
4426}
Here is the call graph for this function:

◆ spellEffectProficiency()

void Spell::spellEffectProficiency ( uint8_t  effectIndex)

Definition at line 622 of file SpellEffects.Legacy.cpp.

623{
624 if (m_playerTarget == nullptr)
625 return;
626
628}
void applyItemProficienciesFromSpell(SpellInfo const *spellInfo, bool apply)
Definition Player.cpp:5253
Here is the call graph for this function:

◆ spellEffectProspecting()

void Spell::spellEffectProspecting ( uint8_t  effectIndex)

◆ SpellEffectProspecting()

void Spell::SpellEffectProspecting ( uint8_t  effectIndex)

Definition at line 5913 of file SpellEffects.Legacy.cpp.

5914{
5915 if (!p_caster) return;
5916
5917 if (!m_itemTarget) // this should never happen
5918 {
5920 return;
5921 }
5922
5923 //Fill Prospecting loot
5925 if (!m_itemTarget->m_loot)
5926 {
5927 m_itemTarget->m_loot = std::make_unique<Loot>();
5928 sLootMgr.fillItemLoot(p_caster, m_itemTarget->m_loot.get(), m_itemTarget->getEntry(), 0);
5929 }
5930
5931 if (m_itemTarget->m_loot->items.size() > 0)
5932 {
5933 sLogger.debugFlag(AscEmu::Logging::LF_SPELL_EFF, "Successfully prospected item {}", uint32_t(m_itemTarget->getEntry()));
5935 }
5936 else // this should never happen either
5937 {
5938 sLogger.debugFlag(AscEmu::Logging::LF_SPELL_EFF, "Prospecting failed, item {} has no loot", uint32_t(m_itemTarget->getEntry()));
5940 }
5941}
@ LOOT_PROSPECTING
Here is the call graph for this function:

◆ SpellEffectPullTowardsDest()

void Spell::SpellEffectPullTowardsDest ( uint8_t  effectIndex)

Definition at line 5044 of file SpellEffects.Legacy.cpp.

5045{
5046 if (!m_unitTarget)
5047 return;
5048
5050 {
5051 sLogger.failure("Spell {} with SPELL_EFFECT_PULL_TOWARDS_DEST has no dest target", m_spellInfo->getId());
5052 return;
5053 }
5054
5056 // This is a blizzlike mistake: this should be 2D distance according to projectile motion formulas, but Blizzard erroneously used 3D distance
5057 float distXY = m_unitTarget->getExactDist(pos);
5058
5059 // Avoid division by 0
5060 if (distXY < 0.001)
5061 return;
5062
5063 float distZ = pos.getPositionZ() - m_unitTarget->GetPositionZ();
5064
5065 float speedXY = m_spellInfo->getEffectMiscValue(effIndex) ? m_spellInfo->getEffectMiscValue(effIndex) / 10.0f : 30.0f;
5066 float speedZ = (2 * speedXY * speedXY * distZ + MovementMgr::gravity * distXY * distXY) / (2 * speedXY * distXY);
5067
5068 if (!std::isfinite(speedZ))
5069 {
5070 sLogger.failure("Spell {} with SPELL_EFFECT_PULL_TOWARDS_DEST called with invalid speedZ.", m_spellInfo->getId());
5071 return;
5072 }
5073
5074 m_unitTarget->jumpTo(speedXY, speedZ, true, pos);
5075}
float getPositionZ() const
float getExactDist(float x, float y, float z) const
Definition Object.hpp:423
void jumpTo(float speedXY, float speedZ, bool forward=true, Optional< LocationVector > dest={})
Definition Unit.cpp:3297
Here is the call graph for this function:

◆ spellEffectQuestComplete()

void Spell::spellEffectQuestComplete ( uint8_t  effectIndex)

◆ SpellEffectQuestComplete()

void Spell::SpellEffectQuestComplete ( uint8_t  effectIndex)

Definition at line 2397 of file SpellEffects.Legacy.cpp.

2398{
2399 if (!p_caster)
2400 return;
2401
2402 if (auto* questLog = p_caster->getQuestLogByQuestId(getSpellInfo()->getEffectMiscValue(effectIndex)))
2403 {
2404 questLog->setStateComplete();
2405 questLog->updatePlayerFields();
2406 questLog->sendQuestComplete();
2407 }
2408}
QuestLogEntry * getQuestLogByQuestId(uint32_t questId) const
Definition Player.cpp:8859
Here is the call graph for this function:

◆ spellEffectRedirectThreat()

void Spell::spellEffectRedirectThreat ( uint8_t  effectIndex)

◆ SpellEffectRedirectThreat()

void Spell::SpellEffectRedirectThreat ( uint8_t  effectIndex)

Definition at line 5953 of file SpellEffects.Legacy.cpp.

5954{
5955 if (!p_caster || !m_unitTarget)
5956 return;
5957
5958 if ((m_unitTarget->isPlayer() && p_caster->getGroup() != static_cast< Player* >(m_unitTarget)->getGroup()) || (m_unitTarget->isCreature() && !m_unitTarget->isPet()))
5959 return;
5960
5962
5963 // Threat Management
5965}
void setMisdirectionTarget(uint64_t PlayerGUID)
Definition Player.hpp:2089
void registerRedirectThreat(uint32_t spellId, uint64_t const &victim, uint32_t pct)
Here is the call graph for this function:

◆ spellEffectReduceThreatPercent()

void Spell::spellEffectReduceThreatPercent ( uint8_t  effectIndex)

◆ SpellEffectReduceThreatPercent()

void Spell::SpellEffectReduceThreatPercent ( uint8_t  effectIndex)

Definition at line 5846 of file SpellEffects.Legacy.cpp.

5847{
5849 return;
5850
5852}
void modifyThreatByPercent(Unit *target, int32_t percent)
float getThreat(Unit const *who, bool includeOffline=false) const
Here is the call graph for this function:

◆ spellEffectRenamePet()

void Spell::spellEffectRenamePet ( uint8_t  effectIndex)

◆ SpellEffectRenamePet()

void Spell::SpellEffectRenamePet ( uint8_t  effectIndex)

Definition at line 6160 of file SpellEffects.Legacy.cpp.

6161{
6162 if (!m_unitTarget || !m_unitTarget->isPet() ||
6163 !static_cast< Pet* >(m_unitTarget)->getPlayerOwner() || static_cast< Pet* >(m_unitTarget)->getPlayerOwner()->getClass() != HUNTER)
6164 return;
6165
6166#if VERSION_STRING == Classic
6168#else
6170#endif
6171}
@ UNIT_FLAG_PET_CAN_BE_RENAMED
@ PET_FLAG_CAN_BE_RENAMED
void addUnitFlags(uint32_t unitFlags)
Definition Unit.cpp:1109
void addPetFlags(uint8_t petFlags)
Definition Unit.cpp:1582
Here is the call graph for this function:

◆ spellEffectReputation()

void Spell::spellEffectReputation ( uint8_t  effectIndex)

◆ SpellEffectReputation()

void Spell::SpellEffectReputation ( uint8_t  effectIndex)

Definition at line 5178 of file SpellEffects.Legacy.cpp.

5179{
5180 if (!m_playerTarget)
5181 return;
5182
5183 m_playerTarget->modFactionStanding(getSpellInfo()->getEffectMiscValue(effectIndex), damage);
5184}
void modFactionStanding(uint32_t faction, int32_t value)
Definition Player.cpp:11448
Here is the call graph for this function:

◆ spellEffectRestoreHealthPct()

void Spell::spellEffectRestoreHealthPct ( uint8_t  effectIndex)

◆ SpellEffectRestoreHealthPct()

void Spell::SpellEffectRestoreHealthPct ( uint8_t  effectIndex)

Definition at line 6173 of file SpellEffects.Legacy.cpp.

6174{
6175 if (m_unitTarget == nullptr || !m_unitTarget->isAlive())
6176 return;
6177
6179}
Here is the call graph for this function:

◆ spellEffectRestorePowerPct()

void Spell::spellEffectRestorePowerPct ( uint8_t  effectIndex)

◆ SpellEffectRestorePowerPct()

void Spell::SpellEffectRestorePowerPct ( uint8_t  effectIndex)

Definition at line 5997 of file SpellEffects.Legacy.cpp.

5998{
5999 if (u_caster == nullptr || m_unitTarget == nullptr || !m_unitTarget->isAlive())
6000 return;
6001
6002 auto power_type = static_cast<PowerType>(getSpellInfo()->getEffectMiscValue(effectIndex));
6003 if (power_type >= TOTAL_PLAYER_POWER_TYPES)
6004 {
6005 sLogger.failure("Unhandled power type {} in {}, report this line to devs.", power_type, __FUNCTION__);
6006 return;
6007 }
6008
6009 uint32_t amount = damage * m_unitTarget->getMaxPower(power_type) / 100;
6010 u_caster->energize(m_unitTarget, getSpellInfo()->getId(), amount, power_type);
6011}
Here is the call graph for this function:

◆ spellEffectResurrect()

void Spell::spellEffectResurrect ( uint8_t  effectIndex)

◆ SpellEffectResurrect()

void Spell::SpellEffectResurrect ( uint8_t  effectIndex)

Definition at line 2420 of file SpellEffects.Legacy.cpp.

2421{
2422 if (!m_playerTarget)
2423 {
2424 if (!m_corpseTarget)
2425 {
2426 // unit resurrection handler
2427 if (m_unitTarget)
2428 {
2430 {
2433
2434 if (!m_unitTarget->isPet())
2435 {
2437 }
2438 else
2439 {
2442 }
2443 m_unitTarget->setHealth(hlth);
2445 m_unitTarget->setTaggerGuid(nullptr);
2448 static_cast< Creature* >(m_unitTarget)->SetLimboState(false); // we can regenerate health now
2449 }
2450 }
2451
2452 return;
2453 }
2454
2455 WoWGuid wowGuid;
2456 wowGuid.Init(m_corpseTarget->getOwnerGuid());
2457
2458 m_playerTarget = sObjectMgr.getPlayer(wowGuid.getGuidLowPart());
2459 if (!m_playerTarget) return;
2460 }
2461
2463 return;
2464
2465 uint32_t health = getSpellInfo()->getEffectBasePoints(effectIndex);
2466 uint32_t mana = getSpellInfo()->getEffectMiscValue(effectIndex);
2467
2470
2473}
@ EVENT_CREATURE_REMOVE_CORPSE
Definition EventMgr.h:36
@ EVENT_PET_DELAYED_REMOVE
Definition EventMgr.h:51
@ ALIVE
uint64_t getOwnerGuid() const
Definition Corpse.cpp:204
void setResurrectMana(uint32_t mana)
Definition Player.cpp:7776
void setResurrectHealth(uint32_t health)
Definition Player.cpp:7775
void SendResurrectRequest(Player *target)
void setTaggerGuid(Unit const *tagger)
Definition Unit.cpp:8103
virtual void setDeathState(DeathState state)
Definition Unit.cpp:7875
void setHealth(uint32_t health)
Definition Unit.cpp:482
void setMoveRoot(bool set_root)
Definition Unit.cpp:2245
bool isDead() const
Definition Unit.cpp:7872
void clear()
Definition Loot.cpp:125
Here is the call graph for this function:

◆ spellEffectResurrectNew()

void Spell::spellEffectResurrectNew ( uint8_t  effectIndex)

◆ SpellEffectResurrectNew()

void Spell::SpellEffectResurrectNew ( uint8_t  effectIndex)

Definition at line 5361 of file SpellEffects.Legacy.cpp.

5362{
5363 //base p =hp,misc mana
5364 if (!m_playerTarget)
5365 {
5366 if (!m_corpseTarget)
5367 {
5368 // unit resurrection handler
5369 if (m_unitTarget)
5370 {
5372 {
5375
5376 if (!m_unitTarget->isPet())
5377 {
5379 }
5380 else
5381 {
5384 }
5385 m_unitTarget->setHealth(hlth);
5387 m_unitTarget->setTaggerGuid(nullptr);
5390 }
5391 }
5392
5393 return;
5394 }
5395
5396 WoWGuid wowGuid;
5397 wowGuid.Init(m_corpseTarget->getOwnerGuid());
5398
5399 m_playerTarget = sObjectMgr.getPlayer(wowGuid.getGuidLowPart());
5400 if (!m_playerTarget) return;
5401 }
5402
5404 return;
5405 //resurrect
5411
5413}
void setResurrectMapId(uint32_t id)
Definition Player.cpp:7778
void setResurrectPosition(LocationVector position)
Definition Player.cpp:7779
void setResurrectInstanceId(uint32_t id)
Definition Player.cpp:7777
Here is the call graph for this function:

◆ spellEffectSanctuary()

void Spell::spellEffectSanctuary ( uint8_t  effectIndex)

◆ SpellEffectSanctuary()

void Spell::SpellEffectSanctuary ( uint8_t  effectIndex)

Definition at line 4696 of file SpellEffects.Legacy.cpp.

4697{
4698 if (!u_caster)
4699 return;
4700
4701 if (p_caster != nullptr)
4703
4704 for (const auto& itr : u_caster->getInRangeObjectsSet())
4705 {
4706 if (itr && itr->isCreature())
4707 static_cast<Creature*>(itr)->getThreatManager().clearThreat(m_unitTarget);
4708 }
4709}
@ SPELL_AURA_MOD_ROOT
Here is the call graph for this function:

◆ spellEffectSchoolDMG()

void Spell::spellEffectSchoolDMG ( uint8_t  effectIndex)

◆ SpellEffectSchoolDMG()

void Spell::SpellEffectSchoolDMG ( uint8_t  effectIndex)

Definition at line 917 of file SpellEffects.Legacy.cpp.

918{
920 return;
921
922 if (m_unitTarget->m_schoolImmunityList[getSpellInfo()->getFirstSchoolFromSchoolMask()])
923 {
925 return;
926 }
927
928 uint32_t dmg = damage;
929 bool static_damage = false;
930 bool force_crit = false;
931
932 if (getSpellInfo()->getEffectChainTarget(effectIndex)) //chain
933 {
934 if (getSpellInfo()->getId() == 32445 || getSpellInfo()->getId() == 28883)
935 {
936 int32_t reduce = (int32_t)(getSpellInfo()->getEffectDamageMultiplier(effectIndex) * 100.0f);
937 reduce -= 100;
938
939 if (reduce && chaindamage)
940 {
941 if (u_caster != nullptr)
942 {
944 }
945 chaindamage += ((getSpellInfo()->getEffectBasePoints(effectIndex) + 51) * reduce / 100);
946 }
947 else
948 {
949 chaindamage = dmg;
950 }
951 dmg = chaindamage;
952 }
953 else
954 {
955 int32_t reduce = (int32_t)(getSpellInfo()->getEffectDamageMultiplier(effectIndex) * 100.0f);
956
957 if (reduce && chaindamage)
958 {
959 if (u_caster != nullptr)
960 {
962 }
963 chaindamage = chaindamage * reduce / 100;
964 }
965 else
966 {
967 chaindamage = dmg;
968 }
969 dmg = chaindamage;
970 }
971 }
972 else
973 {
974 switch (getSpellInfo()->getId())
975 {
976 // SPELL_HASH_METEOR_SLASH:
977 case 45150:
978 {
979 uint32_t splitCount = 0;
980 for (const auto& itr : u_caster->getInRangeOppositeFactionSet())
981 {
982 if (itr && itr->isInFront(u_caster) && u_caster->CalcDistance(itr) <= 65)
983 splitCount++;
984 }
985
986 if (splitCount > 1)
987 dmg = dmg / splitCount;
988 } break;
989
990 // SPELL_HASH_PULSING_SHOCKWAVE: // loken Pulsing shockwave
991 case 52942:
992 case 52961:
993 case 59836:
994 case 59837:
995 {
996 float _distance = u_caster->CalcDistance(m_unitTarget);
997 if (_distance >= 2.0f)
998 dmg = static_cast<uint32_t>(dmg * _distance);
999 } break;
1000
1001 // SPELL_HASH_INCINERATE: // Incinerate -> Deals x-x extra damage if the target is affected by immolate
1002 case 19397:
1003 case 23308:
1004 case 23309:
1005 case 29722:
1006 case 32231:
1007 case 32707:
1008 case 36832:
1009 case 38401:
1010 case 38918:
1011 case 39083:
1012 case 40239:
1013 case 41960:
1014 case 43971:
1015 case 44519:
1016 case 46043:
1017 case 47837:
1018 case 47838:
1019 case 53493:
1020 case 69973:
1021 case 71135:
1022 {
1024 {
1025 // random extra damage
1026 const uint8_t spellRank = getSpellInfo()->hasSpellRanks() ? getSpellInfo()->getRankInfo()->getRank() : 1;
1027 uint32_t extra_dmg = 111 + (spellRank * 11) + Util::getRandomUInt(spellRank * 11);
1028 dmg += extra_dmg;
1029 }
1030 } break;
1031
1032 // SPELL_HASH_ARCANE_SHOT: //hunter - arcane shot
1033 case 3044:
1034 case 14281:
1035 case 14282:
1036 case 14283:
1037 case 14284:
1038 case 14285:
1039 case 14286:
1040 case 14287:
1041 case 27019:
1042 case 34829:
1043 case 35401:
1044 case 36293:
1045 case 36609:
1046 case 36623:
1047 case 38807:
1048 case 49044:
1049 case 49045:
1050 case 51742:
1051 case 55624:
1052 case 58973:
1053 case 69989:
1054 case 71116:
1055 {
1056 if (u_caster)
1058 dmg = Util::float2int32(dmg * (0.9f + Util::getRandomFloat(0.2f))); // randomized damage
1059
1060 if (p_caster != nullptr)
1061 {
1062 dmg = static_cast<uint32_t>(std::round((p_caster->getCalculatedRangedAttackPower() * 0.15) + m_spellInfo->getEffectBasePoints(effectIndex)));
1063 }
1064 } break;
1065
1066 // SPELL_HASH_GORE: // boar/ravager: Gore (50% chance of double damage)
1067 case 4102:
1068 case 32019:
1069 case 35290:
1070 case 35291:
1071 case 35292:
1072 case 35293:
1073 case 35294:
1074 case 35295:
1075 case 35299:
1076 case 35300:
1077 case 35302:
1078 case 35303:
1079 case 35304:
1080 case 35305:
1081 case 35306:
1082 case 35307:
1083 case 35308:
1084 case 48130:
1085 case 51751:
1086 case 59264:
1087 {
1088 dmg *= Util::checkChance(50) ? 2 : 1;
1089 } break;
1090
1091 // SPELL_HASH_THUNDER_CLAP: // Thunderclap
1092 case 6343:
1093 case 8198:
1094 case 8204:
1095 case 8205:
1096 case 11580:
1097 case 11581:
1098 case 13532:
1099 case 25264:
1100 case 47501:
1101 case 47502:
1102 case 57832:
1103 case 60019:
1104 {
1105 if (u_caster)
1107 } break;
1108
1109 // SPELL_HASH_SHOCKWAVE: // Shockwave
1110 case 25425:
1111 case 33686:
1112 case 46968:
1113 case 55636:
1114 case 55918:
1115 case 57728:
1116 case 57741:
1117 case 58947:
1118 case 58977:
1119 case 63783:
1120 case 63982:
1121 case 72149:
1122 case 73499:
1123 case 73794:
1124 case 73795:
1125 case 73796:
1126 case 75343:
1127 case 75417:
1128 case 75418:
1129 {
1130 if (u_caster)
1132 } break;
1133
1134 // SPELL_HASH_JUDGEMENT_OF_COMMAND:
1135 case 20425:
1136 case 20467:
1137 {
1138 if (p_caster != nullptr)
1139 {
1140 if (!m_unitTarget->isStunned())
1141 dmg = dmg >> 1;
1142 if (p_caster->hasAurasWithId(34258))
1143 p_caster->castSpell(p_caster, 34260, true);
1144 if ((p_caster->hasAurasWithId(53696) || p_caster->hasAurasWithId(53695)))
1145 p_caster->castSpell(p_caster, 68055, true);
1146 if (p_caster->hasAurasWithId(37186))
1147 dmg = 33;
1148 }
1149 } break;
1150 case 29386:
1151 case 32778:
1152 case 33554:
1153 case 41368:
1154 case 41470:
1155 case 66005:
1156 case 68017:
1157 case 68018:
1158 case 68019:
1159 case 71551:
1160 {
1161 if (!m_unitTarget->isStunned())
1162 dmg = dmg >> 1;
1163 } break;
1164
1165 // SPELL_HASH_FIRE_STRIKE:
1166 case 7712:
1167 case 7714:
1168 case 7715:
1169 case 7716:
1170 case 7717:
1171 case 7718:
1172 case 7719:
1173 // SPELL_HASH_LIGHTNING_STRIKE:
1174 case 16614:
1175 case 23686:
1176 case 23687:
1177 case 27983:
1178 case 37841:
1179 case 52944:
1180 case 53062:
1181 // SPELL_HASH_MOLTEN_ARMOR: // fire armor, is static damage
1182 case 30482:
1183 case 34913:
1184 case 35915:
1185 case 35916:
1186 case 43043:
1187 case 43044:
1188 case 43045:
1189 case 43046:
1190 {
1191 static_damage = true;
1192 } break;
1193
1194 // SPELL_HASH_EXORCISM:
1195 case 879:
1196 case 5614:
1197 case 5615:
1198 case 10312:
1199 case 10313:
1200 case 10314:
1201 case 17147:
1202 case 17149:
1203 case 27138:
1204 case 33632:
1205 case 48800:
1206 case 48801:
1207 case 52445:
1208 case 58822:
1209 {
1210 if (p_caster != nullptr)
1211 {
1214 dmg += Util::float2int32((0.15f * sph) + (0.15f * ap));
1216 {
1217 uint32_t type = static_cast<Creature*>(m_unitTarget)->GetCreatureProperties()->Type;
1218 if (type == UNIT_TYPE_UNDEAD || type == UNIT_TYPE_DEMON)
1219 force_crit = true;
1220 }
1221 }
1222 } break;
1223
1224 // SPELL_HASH_SHIELD_OF_RIGHTEOUSNESS: // Shield of Righteousness - a bit like "shield slam", OK for both ranks
1225 case 53600:
1226 case 61411:
1227 {
1228 if (p_caster != nullptr)
1229 {
1230#if VERSION_STRING != Classic
1233 dmg = Util::float2int32(1.3f * p_caster->getShieldBlock());
1234#else
1235 dmg += Util::float2int32(1.30f * p_caster->getCombatRating(CR_BLOCK) + getSpellInfo()->getEffectBasePoints(0));
1236#endif
1237 }
1238 } break;
1239
1240 //SPELL_HASH_CONFLAGRATE
1241 case 17962:
1243 break;
1244
1245 //SPELL_HASH_ICE_LANCE
1246 case 30455:
1247 case 31766:
1248 case 42913:
1249 case 42914:
1250 case 43427:
1251 case 43571:
1252 case 44176:
1253 case 45906:
1254 case 46194:
1255 case 49906:
1256 case 54261:
1257 {
1258 // Deal triple damage to frozen targets or to those in Deep Freeze
1260 dmg *= 3;
1261 } break;
1262
1263 //SPELL_HASH_HEROIC_THROW
1264 case 57755:
1265 {
1266 if (u_caster)
1267 dmg = u_caster->getCalculatedAttackPower() / 2 + 12;
1268 if (p_caster != nullptr)
1269 dmg = static_cast<uint32_t>(std::round(p_caster->getCalculatedAttackPower() * 0.5));
1270 } break;
1271
1272 //SPELL_HASH_SHIELD_SLAM
1273 case 8242:
1274 case 15655:
1275 case 23922:
1276 case 23923:
1277 case 23924:
1278 case 23925:
1279 case 25258:
1280 case 29684:
1281 case 30356:
1282 case 30688:
1283 case 46762:
1284 case 47487:
1285 case 47488:
1286 case 49863:
1287 case 59142:
1288 case 69903:
1289 case 72645:
1290 {
1291 if (p_caster != nullptr)
1292 {
1295 {
1296 float block_multiplier = (100.0f + p_caster->m_modBlockAbsorbValue) / 100.0f;
1297 if (block_multiplier < 1.0f)block_multiplier = 1.0f;
1298
1299 int32_t blockable_damage = Util::float2int32((it->getItemProperties()->Block + p_caster->m_modBlockValueFromSpells + p_caster->getCombatRating(CR_BLOCK) + ((p_caster->getStat(STAT_STRENGTH) / 2.0f) - 1.0f)) * block_multiplier);
1300
1301 /*
1302 3.2.0:
1303 The benefit from additional block value this ability gains is now subject
1304 to diminishing returns. Diminishing returns occur once block value exceeds
1305 30 times the player's level and caps the maximum damage benefit from shield
1306 block value at 34.5 times the player's level.
1307 */
1308 int32_t max_blockable_damage = static_cast<int32_t>(p_caster->getLevel() * 34.5f);
1309 if (blockable_damage > max_blockable_damage)
1310 {
1311 blockable_damage = max_blockable_damage;
1312 }
1313
1314 dmg += blockable_damage;
1315
1316 }
1317 }
1318 } break;
1319
1320 //SPELL_HASH_BLOODTHIRST
1321 case 23880:
1322 case 23881:
1323 {
1324 if (p_caster != nullptr)
1325 {
1326 dmg = static_cast<uint32_t>(std::round(p_caster->getCalculatedAttackPower() * 0.5));
1327 break;
1328 }
1329 }
1330 case 23885:
1331 case 23892:
1332 case 23893:
1333 case 23894:
1334 case 25251:
1335 case 30335:
1336 case 30474:
1337 case 30475:
1338 case 30476:
1339 case 31996:
1340 case 31997:
1341 case 31998:
1342 case 33964:
1343 case 35123:
1344 case 35125:
1345 case 35947:
1346 case 35948:
1347 case 35949:
1348 case 39070:
1349 case 39071:
1350 case 39072:
1351 case 40423:
1352 case 55968:
1353 case 55969:
1354 case 55970:
1355 case 57790:
1356 case 57791:
1357 case 57792:
1358 case 60017:
1359 case 71938:
1360 {
1362 } break;
1363
1364 //SPELL_HASH_CONCUSSION_BLOW
1365 case 12809:
1366 case 22427:
1367 case 32588:
1368 case 52719:
1369 case 54132:
1370 {
1371 //3.2.2
1372 //[Concussion Blow]: The damage done by this ability has been reduced by 50%,
1373 //but its threat generation will remain approximately the same.
1375 } break;
1376
1377 // SPELL_HASH_INTERCEPT
1378 case 20252:
1379 {
1380 if (p_caster != nullptr)
1381 {
1382 dmg = static_cast<uint32_t>(std::round(p_caster->getCalculatedAttackPower() * 0.12));
1383 break;
1384 }
1385 }
1386 case 20253:
1387 case 20614:
1388 case 20615:
1389 case 20616:
1390 case 20617:
1391 case 25272:
1392 case 25273:
1393 case 25274:
1394 case 25275:
1395 case 27577:
1396 case 27826:
1397 case 30151:
1398 case 30153:
1399 case 30154:
1400 case 30194:
1401 case 30195:
1402 case 30197:
1403 case 30198:
1404 case 30199:
1405 case 30200:
1406 case 47995:
1407 case 47996:
1408 case 50823:
1409 case 58743:
1410 case 58747:
1411 case 58769:
1412 case 61490:
1413 case 61491:
1414 case 67540:
1415 case 67573:
1416 {
1417 if (u_caster)
1419 } break;
1420
1421 case 5308:
1422 case 20658:
1423 case 20660:
1424 case 20661:
1425 case 20662:
1426 case 25234:
1427 case 25236:
1428 case 47470:
1429 case 47471:
1430 {
1431 if (p_caster != nullptr)
1433 }break;
1434
1435 //SPELL_HASH_SHIELD_SLAM
1436 /* Zyres 10/06/2017: Already defined!
1437 case 23922:
1438 case 23923:
1439 case 23924:
1440 case 23925:
1441 case 25258:
1442 case 30356:
1443 case 47487:
1444 case 47488:
1445 {
1446 if (p_caster != NULL)
1447 {
1448#if VERSION_STRING != Classic
1449 Item* it = static_cast<Item*>(p_caster->getItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_OFFHAND));
1450 if (it && it->getItemProperties() && it->getItemProperties()->InventoryType == INVTYPE_SHIELD)
1451 dmg = p_caster->getUInt32Value(PLAYER_SHIELD_BLOCK);
1452#endif
1453 }
1454 }break;*/
1455 case 34428:
1456 {
1457 if (p_caster != nullptr)
1458 {
1460 dmg = (p_caster->getCalculatedAttackPower()*(m_spellInfo->getEffectBasePoints(effectIndex) + 1)) / 100;
1461 }
1462 }break;
1463 case 6572:
1464 case 6574:
1465 case 7379:
1466 case 11600:
1467 case 11601:
1468 case 25288:
1469 case 25269:
1470 case 30357:
1471 case 57823:
1472 {
1473 if (p_caster != nullptr)
1474 dmg = static_cast<uint32_t>(std::round(p_caster->getCalculatedAttackPower() * 0.207));
1475 }break;
1476
1477 case 64382:
1478 if (p_caster != nullptr)
1479 dmg = static_cast<uint32_t>(std::round(p_caster->getCalculatedAttackPower() * 0.5));
1480 break;
1481
1482 case 29707:
1483 case 30324:
1484 case 47449:
1485 case 47450:
1486 {
1487 /* Possibly broken (infinity loop) -- ask Zyres
1488 if (p_caster != nullptr)
1489 {
1490 if (m_unitTarget->isDazed())
1491 for (uint32_t i = UNIT_FIELD_AURASTATE; i < AURASTATE_FLAG_SWIFTMEND; i)
1492 {
1493 switch (m_spellInfo->getId())
1494 { // This info isn't in the dbc files.....
1495 case 29707:
1496 dmg = static_cast<uint32_t>(std::round(81.9));
1497 break;
1498 case 30324:
1499 dmg = static_cast<uint32_t>(std::round(110.95));
1500 break;
1501 case 47449:
1502 dmg = static_cast<uint32_t>(std::round(151.2));
1503 break;
1504 case 47450:
1505 dmg = static_cast<uint32_t>(std::round(173.25));
1506 break;
1507 }
1508 }
1509 }
1510 */
1511 }break;
1512 case 845:
1513 case 7369:
1514 case 11608:
1515 case 11609:
1516 case 20569:
1517 case 25231:
1518 case 47519:
1519 case 47520:
1520 {
1521 if (p_caster != nullptr)
1522 {
1524 if (item != nullptr)
1525 {
1526 if (p_caster->hasAurasWithId(12329))
1527 dmg = static_cast<uint32_t>(std::round((((item->getItemProperties()->Damage[0].Min + item->getItemProperties()->Damage[0].Max) * 0.2f) + m_spellInfo->getEffectBasePoints(effectIndex)) * 0.4));
1528 else if (p_caster->hasAurasWithId(12950))
1529 dmg = static_cast<uint32_t>(std::round((((item->getItemProperties()->Damage[0].Min + item->getItemProperties()->Damage[0].Max) * 0.2f) + m_spellInfo->getEffectBasePoints(effectIndex)) * 0.8));
1530 else if (p_caster->hasAurasWithId(20496))
1531 dmg = static_cast<uint32_t>(std::round((((item->getItemProperties()->Damage[0].Min + item->getItemProperties()->Damage[0].Max) * 0.2f) + m_spellInfo->getEffectBasePoints(effectIndex)) * 1.2));
1532 else
1533 dmg = static_cast<uint32_t>(std::round(((item->getItemProperties()->Damage[0].Min + item->getItemProperties()->Damage[0].Max) * 0.2f) + m_spellInfo->getEffectBasePoints(effectIndex)));
1534 }
1535 }
1536 }break;
1537 // Slam
1538 case 1464:
1539 case 8820:
1540 case 11604:
1541 case 11605:
1542 case 25241:
1543 case 25242:
1544 case 47474:
1545 case 47475:
1546 {
1547 if (p_caster != nullptr)
1548 {
1550 if (item != nullptr)
1551 dmg = static_cast<uint32_t>(std::round(((item->getItemProperties()->Damage[0].Min + item->getItemProperties()->Damage[0].Max) * 0.2f) + m_spellInfo->getEffectBasePoints(effectIndex)));
1552 }
1553 }break;
1554
1555 case 31898:
1556 case 31804:
1557 case 20187:
1558 case 53733:
1559 case 57774:
1560 case 20268:
1561 case 53726:
1562 {
1563 if (p_caster != nullptr)
1564 {
1565 if (p_caster->hasAurasWithId(34258))
1566 p_caster->castSpell(p_caster, 34260, true);
1567 if ((p_caster->hasAurasWithId(53696) || p_caster->hasAurasWithId(53695)))
1568 p_caster->castSpell(p_caster, 68055, true);
1569 if (p_caster->hasAurasWithId(37186))
1570 dmg = 33;
1571 }
1572 }break;
1573
1574 case 25742:
1575 {
1576 if (p_caster != nullptr)
1577 dmg = static_cast<uint32_t>(std::round(p_caster->getBaseAttackTime(MELEE) / 1000 * ((0.022 * (p_caster->getCalculatedAttackPower()) + (0.044 * (p_caster->GetDamageDoneMod(1))))) + m_spellInfo->getEffectBasePoints(effectIndex)));
1578 }break;
1579 case 19434:
1580 case 20900:
1581 case 20901:
1582 case 20902:
1583 case 20903:
1584 case 20904:
1585 case 27065:
1586 case 49049:
1587 case 49050:
1588 {
1589 if (p_caster != nullptr)
1590 {
1592 if (item != nullptr)
1593 dmg = static_cast<uint32_t>(std::round(((item->getItemProperties()->Damage[0].Min + item->getItemProperties()->Damage[0].Max) * 0.2f) + m_spellInfo->getEffectBasePoints(effectIndex)));
1594
1595 }
1596 }break;
1597 case 53209:
1598 {
1599 if (p_caster != nullptr)
1600 {
1602 if (item != nullptr)
1603 dmg = static_cast<uint32_t>(std::round(((item->getItemProperties()->Damage[0].Min + item->getItemProperties()->Damage[0].Max) * 0.2f) * 1.25));
1604 }
1605 }break;
1606 case 56641:
1607 case 34120:
1608 case 49051:
1609 case 49052:
1610 {
1611#if VERSION_STRING < Cata
1612 if (p_caster != nullptr)
1613 {
1615 ItemProperties const* pItemProto = sMySQLStore.getItemProperties(p_caster->getAmmoId());
1616 uint32_t stundmg;
1617 float bowdmg;
1618 float ammodmg;
1619 if (m_unitTarget->isDazed())
1620 stundmg = p_caster->getCalculatedRangedAttackPower() / 10 + m_spellInfo->getEffectBasePoints(effectIndex) + m_spellInfo->getEffectBasePoints(effectIndex + 1);
1621 else
1623 if (pItem)
1624 bowdmg = (pItem->getItemProperties()->Damage[0].Min + pItem->getItemProperties()->Damage[0].Max) * 0.2f;
1625 else
1626 bowdmg = 0;
1627 if (pItemProto)
1628 ammodmg = (pItemProto->Damage[0].Min + pItemProto->Damage[0].Max) * 0.2f;
1629 else
1630 ammodmg = 0;
1631
1632 dmg = Util::float2int32(ammodmg + bowdmg) + stundmg;
1633 }
1634#endif
1635 }break;
1636 case 64422: // Sonic Screech, Auriaya encounter
1637 case 64688:
1638 {
1639 if (u_caster != nullptr)
1640 {
1641 int splitCount = 0;
1642 for (const auto& itr : u_caster->getInRangeOppositeFactionSet())
1643 {
1644 if (itr && itr->isInFront(u_caster))
1645 splitCount++;
1646 }
1647
1648 if (splitCount > 1)
1649 dmg /= splitCount;
1650 }
1651 }
1652 break;
1653 default:
1654 break;
1655 };
1656 }
1657
1658 if (p_caster && !static_damage) //this is wrong but with current spell coef system it has to be here...
1659 {
1660 switch (p_caster->getClass())
1661 {
1662 case WARRIOR:
1663 case ROGUE:
1664 case HUNTER:
1665#if VERSION_STRING > TBC
1666 case DEATHKNIGHT:
1667#endif
1668 static_damage = true; //No spells from these classes benefit from spell damage. Prevents Arc hunters, frost DKs, etc.
1669 break;
1670 default:
1671 break;
1672 }
1673 }
1674
1675
1676 // check for no more damage left (chains)
1677 if (!dmg)
1678 dmg = getSpellInfo()->getEffectBasePoints(effectIndex);
1679
1680 if (!dmg)
1681 return;
1682
1683 if (getSpellInfo()->getSpeed() > 0 && m_triggeredSpell == false)
1684 {
1685 m_targetDamageInfo = m_caster->doSpellDamage(m_unitTarget, getSpellInfo()->getId(), static_cast<float_t>(dmg), effectIndex, pSpellId != 0, false, false, isForcedCrit, this);
1686 isTargetDamageInfoSet = true;
1687 }
1688 else
1689 {
1691 {
1692 m_targetDamageInfo = m_caster->doSpellDamage(m_unitTarget, getSpellInfo()->getId(), static_cast<float_t>(dmg), effectIndex, m_triggeredSpell, false, false, isForcedCrit, this);
1693 isTargetDamageInfoSet = true;
1694 }
1695 else
1696 {
1697 if (u_caster != nullptr)
1698 {
1699 WeaponDamageType _type;
1701 _type = RANGED;
1702 else
1703 {
1704 if (getSpellInfo()->getAttributesExC() & ATTRIBUTESEXC_REQUIRES_OFFHAND_WEAPON)
1705 _type = OFFHAND;
1706 else
1707 _type = MELEE;
1708 }
1709
1710 m_targetDamageInfo = u_caster->strike(m_unitTarget, _type, getSpellInfo(), 0, 0, dmg, m_triggeredSpell, true, (force_crit || isForcedCrit), this);
1711 isTargetDamageInfoSet = true;
1712 }
1713 }
1714 }
1715}
@ AURASTATE_FLAG_CONFLAGRATE
@ AURASTATE_FLAG_FROZEN
@ INVTYPE_SHIELD
@ CR_BLOCK
@ DEATHKNIGHT
@ ROGUE
@ WARRIOR
@ STAT_STRENGTH
Definition Stats.h:33
uint32_t getCombatRating(uint8_t combatRating) const
Definition Player.cpp:1276
uint32_t getShieldBlock() const
Definition Player.cpp:1113
int32_t GetDamageDoneMod(uint16_t school) override
Definition Player.hpp:1939
uint32_t m_modBlockValueFromSpells
Definition Player.hpp:2049
uint32_t m_modBlockAbsorbValue
Definition Player.hpp:2048
SpellRankInfo const * getRankInfo() const
uint32_t isStunned() const
Definition Unit.hpp:1351
uint32_t getStat(uint8_t stat) const
Definition Unit.cpp:1448
uint8_t getRank() const
Definition SpellInfo.cpp:31
Here is the call graph for this function:

◆ spellEffectScriptEffect()

void Spell::spellEffectScriptEffect ( uint8_t  effectIndex)

Definition at line 642 of file SpellEffects.Legacy.cpp.

643{
644 // Check that the scripted effect is handled properly in spell script
645 // In case it's not, send error log
646 const auto scriptResult = sScriptMgr.callScriptedSpellOnDummyOrScriptedEffect(this, effectIndex);
647 if (scriptResult == SpellScriptCheckDummy::DUMMY_OK)
648 return;
649
650 // Legacy scripts
651 if (sScriptMgr.CallScriptedDummySpell(m_spellInfo->getId(), effectIndex, this))
652 return;
653
654 // Legacy scripts
655 if (sScriptMgr.HandleScriptedSpellEffect(m_spellInfo->getId(), effectIndex, this))
656 return;
657
658 sLogger.failure("Spell::spellEffectScriptEffect : Spell {} ({}) has a scripted effect index (%hhu), but no handler for it.", m_spellInfo->getId(), m_spellInfo->getName(), effectIndex);
659}
Here is the call graph for this function:

◆ spellEffectSelfResurrect()

void Spell::spellEffectSelfResurrect ( uint8_t  effectIndex)

◆ SpellEffectSelfResurrect()

void Spell::SpellEffectSelfResurrect ( uint8_t  effectIndex)

Definition at line 4904 of file SpellEffects.Legacy.cpp.

4905{
4906 if (!p_caster || !m_unitTarget || m_playerTarget->isAlive()) return;
4907
4908 uint32_t mana;
4909 uint32_t health;
4910 uint32_t class_ = m_unitTarget->getClass();
4911
4912 switch (getSpellInfo()->getId())
4913 {
4914 case 3026:
4915 case 20758:
4916 case 20759:
4917 case 20760:
4918 case 20761:
4919 case 27240:
4920 case 47882:
4921 {
4922 health = getSpellInfo()->getEffectMiscValue(effectIndex);
4923 mana = -damage;
4924 }
4925 break;
4926 case 21169: //Reincarnation. Resurrect with 20% health and mana
4927 {
4928 int32_t amt = damage;
4929 health = uint32_t((m_unitTarget->getMaxHealth() * amt) / 100);
4930 mana = uint32_t((m_unitTarget->getMaxPower(POWER_TYPE_MANA) * amt) / 100);
4931 }
4932 break;
4933 default:
4934 {
4935 if (damage < 0) return;
4936 health = uint32_t(m_unitTarget->getMaxHealth() * damage / 100);
4938 }
4939 break;
4940 }
4941
4942 if (class_ == WARRIOR || class_ == ROGUE)
4943 mana = 0;
4944
4947
4950
4952
4953 if (getSpellInfo()->getId() == 21169)
4955}
void setSelfResurrectSpell(uint32_t spell)
Definition Player.cpp:1136
void resurrect()
Definition Player.cpp:7671
Here is the call graph for this function:

◆ spellEffectSendEvent()

void Spell::spellEffectSendEvent ( uint8_t  effectIndex)

◆ SpellEffectSendEvent()

void Spell::SpellEffectSendEvent ( uint8_t  effectIndex)

Definition at line 4337 of file SpellEffects.Legacy.cpp.

4338{
4339 //This is mostly used to trigger events on quests or some places
4340
4341 if (sScriptMgr.CallScriptedDummySpell(m_spellInfo->getId(), effectIndex, this))
4342 return;
4343
4344 if (sScriptMgr.HandleScriptedSpellEffect(m_spellInfo->getId(), effectIndex, this))
4345 return;
4346
4347 sLogger.debugFlag(AscEmu::Logging::LF_SPELL_EFF, "Spell ID: {} ({}) has a scripted effect index ({}) but no handler for it.", m_spellInfo->getId(), m_spellInfo->getName(), effectIndex);
4348
4349}
Here is the call graph for this function:

◆ spellEffectSetMirrorName()

void Spell::spellEffectSetMirrorName ( uint8_t  effectIndex)

◆ spellEffectSkill()

void Spell::spellEffectSkill ( uint8_t  effectIndex)

Definition at line 661 of file SpellEffects.Legacy.cpp.

662{
663 if (m_playerTarget == nullptr)
664 return;
665
666 const auto skillLine = static_cast<uint16_t>(getSpellInfo()->getEffectMiscValue(effectIndex));
667 const auto amount = static_cast<uint16_t>(damage * 75);
668
669 if (m_playerTarget->hasSkillLine(skillLine))
670 {
671 if (amount > m_playerTarget->getSkillLineMax(skillLine))
672 m_playerTarget->modifySkillMaximum(skillLine, amount);
673 }
674 else
675 {
676 m_playerTarget->addSkillLine(skillLine, 1, amount);
677 }
678}
void modifySkillMaximum(uint16_t skillLine, uint16_t maxValue)
Definition Player.cpp:5022
Here is the call graph for this function:

◆ spellEffectSkillStep()

void Spell::spellEffectSkillStep ( uint8_t  effectIndex)

Definition at line 593 of file SpellEffects.Legacy.cpp.

594{
595 if (m_playerTarget == nullptr)
596 return;
597
598 auto skillId = static_cast<uint16_t>(getSpellInfo()->getEffectMiscValue(effectIndex));
599#if VERSION_STRING <= WotLK
600 // TODO: check if this is needed anymore
601 // Legacy comment: somehow for lockpicking misc is different than the skill :s
602 if (skillId == 242)
603 skillId = SKILL_LOCKPICKING;
604#endif
605
606 const auto skillLine = sSkillLineStore.lookupEntry(skillId);
607 if (skillLine == nullptr)
608 return;
609
610 // Set new skill maximum value for professions only
611 // Other types will be handled on skill apply
612 uint16_t max = 0;
613 if (skillLine->type == SKILL_TYPE_PROFESSION || skillLine->type == SKILL_TYPE_SECONDARY)
614 max = static_cast<uint16_t>(damage * 75);
615
616 if (m_playerTarget->hasSkillLine(skillId))
617 m_playerTarget->modifySkillMaximum(skillId, max);
618 else
619 m_playerTarget->addSkillLine(skillId, 1, max);
620}
@ SKILL_TYPE_SECONDARY
Definition Skill.hpp:282
@ SKILL_TYPE_PROFESSION
Definition Skill.hpp:284
SERVER_DECL WDB::WDBContainer< WDB::Structures::SkillLineEntry > sSkillLineStore
Definition WDBStores.cpp:97
Here is the call graph for this function:

◆ spellEffectSkinning()

void Spell::spellEffectSkinning ( uint8_t  effectIndex)

◆ SpellEffectSkinning()

void Spell::SpellEffectSkinning ( uint8_t  effectIndex)

Definition at line 4957 of file SpellEffects.Legacy.cpp.

4958{
4960 return;
4961
4962 Creature* cr = static_cast<Creature*>(m_unitTarget);
4963 auto skill = cr->GetRequiredLootSkill();
4964 auto sk = static_cast<Player*>(m_caster)->getSkillLineCurrent(skill);
4965 uint32_t lvl = cr->getLevel();
4966
4967 if ((sk >= lvl * 5) || ((sk + 100U) >= lvl * 10))
4968 {
4969 //Fill loot for Skinning
4970 sLootMgr.fillSkinningLoot(p_caster, &cr->loot, m_unitTarget->getEntry(), 0);
4971 static_cast<Player*>(m_caster)->sendLoot(m_unitTarget->getGuid(), LOOT_SKINNING, m_unitTarget->GetMapId());
4972
4973 //Not skinable again
4975 cr->Skinned = true;
4976
4977 if (cr->GetCreatureProperties()->Rank > 0)
4978 DetermineSkillUp(skill, sk < lvl * 5 ? sk / 5 : lvl, 2);
4979 else
4980 DetermineSkillUp(skill, sk < lvl * 5 ? sk / 5 : lvl, 1);
4981 }
4982 else
4983 {
4985 }
4986}
uint16_t GetRequiredLootSkill()
bool Skinned
Definition Creature.h:267
void removeUnitFlags(uint32_t unitFlags)
Definition Unit.cpp:1110
Here is the call graph for this function:

◆ spellEffectSkinPlayerCorpse()

void Spell::spellEffectSkinPlayerCorpse ( uint8_t  effectIndex)

◆ SpellEffectSkinPlayerCorpse()

void Spell::SpellEffectSkinPlayerCorpse ( uint8_t  effectIndex)

Definition at line 5439 of file SpellEffects.Legacy.cpp.

5440{
5441 Corpse* corpse = nullptr;
5442 if (!m_playerTarget)
5443 {
5444 // means we're "skinning" a corpse
5445 corpse = sObjectMgr.getCorpseByGuid((uint32_t)m_targets.getUnitTargetGuid()); // hacky
5446 }
5447 else if (m_playerTarget->getDeathState() == CORPSE) // repopped while we were casting
5448 {
5449 corpse = sObjectMgr.getCorpseByGuid(m_playerTarget->getGuidLow());
5450 }
5451
5452 if (p_caster == nullptr)
5453 return;
5454
5455 if (m_playerTarget && !corpse)
5456 {
5458 return;
5459
5460 // Set all the lootable stuff on the player. If he repops before we've looted, we'll set the flags
5461 // on corpse then :p
5462
5466
5467 // Send the loot.
5469
5470 // Send a message to the died player, telling him he has to resurrect at the graveyard.
5471 // Send an empty corpse location too, :P
5472
5473 m_playerTarget->sendPacket(MsgCorspeQuery(0).serialise().get());
5474
5475 // don't allow him to spawn a corpse
5477
5478 // and.. force him to the graveyard and repop him.
5480
5481 }
5482 else if (corpse)
5483 {
5484 // find the corpses' owner
5485 WoWGuid wowGuid;
5486 wowGuid.Init(corpse->getOwnerGuid());
5487
5488 Player* owner = sObjectMgr.getPlayer(wowGuid.getGuidLowPart());
5489 if (owner)
5490 {
5491 if (!owner->getBattleground())
5492 return;
5493
5494 owner->sendPacket(MsgCorspeQuery(0).serialise().get());
5495 }
5496
5497 if (corpse->getDynamicFlags() != 1)
5498 corpse->setDynamicFlags(1); // sets it so you can loot the plyr
5499
5500 // remove skinnable flag
5502
5503 // remove owner association
5504 corpse->setOwnerNotifyMap(0);
5506
5507 // send loot
5508 p_caster->sendLoot(corpse->getGuid(), LOOT_SKINNING, corpse->GetMapId());
5509
5510 corpse->deleteFromDB();
5511 sObjectMgr.addCorpseDespawnTime(corpse);
5512 }
5513}
@ CORPSE_FLAG_UNK1
Definition Corpse.hpp:24
@ CORPSE_FLAG_BONE
Definition Corpse.hpp:22
@ CORPSE
@ U_DYN_FLAG_LOOTABLE
void deleteFromDB()
Definition Corpse.cpp:141
void setCorpseState(uint32_t state)
Definition Corpse.cpp:152
void setOwnerNotifyMap(uint64_t guid)
Definition Corpse.cpp:155
void setDynamicFlags(uint32_t flags)
Definition Corpse.cpp:252
void setFlags(uint32_t flags)
Definition Corpse.cpp:249
uint32_t getDynamicFlags() const
Definition Corpse.cpp:251
void addDynamicFlags(uint16_t dynamicFlags)
Definition Object.cpp:395
void repopRequest()
Definition Player.cpp:7545
void setAllowedToCreateCorpse(bool allowed)
Definition Player.cpp:7435
void setLootableOnCorpse(bool lootable)
Definition Player.cpp:11310
DeathState getDeathState() const
Definition Unit.cpp:7924
Here is the call graph for this function:

◆ spellEffectSpawn()

void Spell::spellEffectSpawn ( uint8_t  effectIndex)

◆ SpellEffectSpawn()

void Spell::SpellEffectSpawn ( uint8_t  effectIndex)

Definition at line 3911 of file SpellEffects.Legacy.cpp.

3912{
3913 // this effect is mostly for custom teleporting
3914 switch (getSpellInfo()->getId())
3915 {
3916 case 10418: // Arugal spawn-in spell , teleports it to 3 locations randomly sneaking players (bastard ;P)
3917 {
3918 //only Creature can cast this spell
3919 if (u_caster == nullptr || p_caster != nullptr)
3920 return;
3921
3922 //static float coord[3][3] = { { -108.9034f, 2129.5678f, 144.9210f }, { -108.9034f, 2155.5678f, 155.678f }, { -77.9034f, 2155.5678f, 155.678f } };
3923
3924 // uint8_t j = RandomUInt(3);
3925 //u_caster->getAIInterface()->SendMoveToPacket(coord[j][0],coord[j][1],coord[j][2],0.0f,0,u_caster->getAIInterface()->getMoveFlags());
3926 }
3927 }
3928}
Here is the call graph for this function:

◆ spellEffectSpellDefense()

void Spell::spellEffectSpellDefense ( uint8_t  effectIndex)

◆ SpellEffectSpellDefense()

void Spell::SpellEffectSpellDefense ( uint8_t  effectIndex)

Definition at line 3787 of file SpellEffects.Legacy.cpp.

3788{
3789 //used to enable this ability. We use it all the time ...
3790}

◆ spellEffectSpellSteal()

void Spell::spellEffectSpellSteal ( uint8_t  effectIndex)

◆ SpellEffectSpellSteal()

void Spell::SpellEffectSpellSteal ( uint8_t  effectIndex)

Definition at line 5854 of file SpellEffects.Legacy.cpp.

5855{
5856 if (m_unitTarget == nullptr || u_caster == nullptr || !m_unitTarget->isAlive())
5857 return;
5858
5859 if (m_playerTarget != nullptr && p_caster != nullptr && p_caster != m_playerTarget)
5860 {
5863 }
5864
5865 uint16_t start, end;
5867 {
5870 }
5871 else
5872 return;
5873
5874 std::list< uint32_t > stealedSpells;
5875
5876 for (auto x = start; x < end; x++)
5877 {
5878 if (auto* const aur = m_unitTarget->getAuraWithAuraSlot(x))
5879 {
5880 SpellInfo const* aursp = aur->getSpellInfo();
5881
5882 if (aursp->getId() != 15007 && !aur->IsPassive()
5883 // && aur->IsPositive() // Zack : We are only checking positive auras. There is no meaning to check again
5884 ) //Nothing can dispel resurrection sickness
5885 {
5886 if (aursp->getDispelType() == DISPEL_MAGIC)
5887 {
5888 stealedSpells.push_back(aursp->getId());
5889
5890 uint32_t aurdur = (aur->getTimeLeft() > 120000 ? 120000 : aur->getTimeLeft());
5891 auto aura = sSpellMgr.newAura(aursp, aurdur, u_caster, u_caster);
5893 for (uint8_t j = 0; j < 3; j++)
5894 {
5895 if (aura->getSpellInfo()->getEffect(j))
5896 {
5897 aura->addAuraEffect(static_cast<AuraEffect>(aura->getSpellInfo()->getEffectApplyAuraName(j)), aura->getSpellInfo()->getEffectBasePoints(j) + 1, aura->getSpellInfo()->getEffectMiscValue(j), aur->getAuraEffect(j)->getEffectPercentModifier(), true, j);
5898 }
5899 }
5900 u_caster->addAura(std::move(aura));
5901 break;
5902 }
5903 }
5904 }
5905 }
5906
5907 if (!stealedSpells.empty())
5908 {
5909 m_caster->sendMessageToSet(SmsgSpellStealLog(m_caster->getGuid(), m_unitTarget->getGuid(), getSpellInfo()->getId(), stealedSpells).serialise().get(), true);
5910 }
5911}
uint32_t removeAllAurasByIdReturnCount(uint32_t auraId, AuraRemoveMode mode=AURA_REMOVE_BY_SERVER)
Definition Unit.cpp:5471
Here is the call graph for this function:

◆ spellEffectStartTaxi()

void Spell::spellEffectStartTaxi ( uint8_t  effectIndex)

◆ SpellEffectStartTaxi()

void Spell::SpellEffectStartTaxi ( uint8_t  effectIndex)

Definition at line 5799 of file SpellEffects.Legacy.cpp.

5800{
5802 return;
5803
5805 return;
5806
5808}
bool activateTaxiPathTo(std::vector< uint32_t > const &nodes, Creature *npc=nullptr, uint32_t spellid=0)
Definition Player.cpp:10513
Here is the call graph for this function:

◆ spellEffectStuck()

void Spell::spellEffectStuck ( uint8_t  effectIndex)

◆ SpellEffectStuck()

void Spell::SpellEffectStuck ( uint8_t  effectIndex)

Definition at line 4771 of file SpellEffects.Legacy.cpp.

4772{
4774 return;
4775
4778 /*
4779 playerTarget->SafeTeleport(playerTarget->getBindMapId(), 0, playerTarget->GetBindPositionX(), playerTarget->GetBindPositionY(), playerTarget->GetBindPositionZ(), 3.14f);*/
4780}
Here is the call graph for this function:

◆ spellEffectSummon()

void Spell::spellEffectSummon ( uint8_t  effectIndex)

◆ SpellEffectSummon()

void Spell::SpellEffectSummon ( uint8_t  effectIndex)
virtual

Definition at line 2825 of file SpellEffects.Legacy.cpp.

2826{
2827 uint32_t summonpropid = m_spellInfo->getEffectMiscValueB(effectIndex);
2828
2829 auto summon_properties = sSummonPropertiesStore.lookupEntry(summonpropid);
2830 if (summon_properties == nullptr)
2831 {
2832 sLogger.failure("No SummonPropertiesEntry for Spell {} ({})", m_spellInfo->getId(), m_spellInfo->getName());
2833 return;
2834 }
2835
2836 uint32_t entry = m_spellInfo->getEffectMiscValue(effectIndex);
2837
2838 CreatureProperties const* cp = sMySQLStore.getCreatureProperties(entry);
2839
2840 if (cp == nullptr)
2841 {
2842 sLogger.failure("Spell {} ({}) tried to summon creature {} without database data", m_spellInfo->getId(), m_spellInfo->getName(), entry);
2843 return;
2844 }
2845
2846 LocationVector v(0.0f, 0.0f, 0.0f, 0.0f);
2847
2848 if ((m_targets.hasDestination()) != 0)
2850 else
2851 v = m_caster->GetPosition();
2852
2853 // Ugly hack to make sure we always summon at least 1
2854 if (damage == 0)
2855 damage = 1;
2856
2857 // Client adds these spells to the companion window, it's weird but then it happens anyways
2858 if (summon_properties->Slot == 5)
2859 {
2860 SpellEffectSummonCompanion(effectIndex, summon_properties, cp, v);
2861 return;
2862 }
2863
2864 switch (summon_properties->ControlType)
2865 {
2867 if (summon_properties->ID == 121)
2868 {
2869 spellEffectSummonTotem(effectIndex, summon_properties, cp, v);
2870 return;
2871 }
2872 break;
2873
2875 SpellEffectSummonTemporaryPet(effectIndex, summon_properties, cp, v);
2876 return;
2877
2879 SpellEffectSummonPossessed(effectIndex, summon_properties, cp, v);
2880 return;
2881
2883 SpellEffectSummonVehicle(effectIndex, summon_properties, cp, v);
2884 return;
2886 if (summon_properties->Flags & 512)
2887 {
2888 SpellEffectSummonGuardian(effectIndex, summon_properties, cp, v);
2889 return;
2890 }
2891 }
2892
2893 switch (summon_properties->Type)
2894 {
2895 case SUMMON_TYPE_NONE:
2898
2899 if (summon_properties->ControlType == SUMMON_CONTROL_TYPE_GUARDIAN)
2900 SpellEffectSummonGuardian(effectIndex, summon_properties, cp, v);
2901 else
2902 SpellEffectSummonWild(effectIndex);
2903
2904 return;
2905
2906 case SUMMON_TYPE_PET:
2907 SpellEffectSummonTemporaryPet(effectIndex, summon_properties, cp, v);
2908 return;
2909
2911 case SUMMON_TYPE_MINION:
2913 SpellEffectSummonGuardian(effectIndex, summon_properties, cp, v);
2914 return;
2915
2916 case SUMMON_TYPE_TOTEM:
2917 spellEffectSummonTotem(effectIndex, summon_properties, cp, v);
2918 return;
2919
2921 // These are used as guardians in some quests
2922 if (summon_properties->Slot == 6)
2923 SpellEffectSummonGuardian(effectIndex, summon_properties, cp, v);
2924 else
2925 SpellEffectSummonCompanion(effectIndex, summon_properties, cp, v);
2926 return;
2927
2929 case SUMMON_TYPE_MOUNT:
2930 SpellEffectSummonVehicle(effectIndex, summon_properties, cp, v);
2931 return;
2932
2934 SpellEffectSummonGuardian(effectIndex, summon_properties, cp, v);
2935 return;
2936 }
2937
2938 sLogger.failure("Unknown summon type in summon property {} in spell {} {}", summonpropid, m_spellInfo->getId(), m_spellInfo->getName());
2939}
@ SUMMON_CONTROL_TYPE_GUARDIAN
@ SUMMON_CONTROL_TYPE_VEHICLE
@ SUMMON_CATEGORY_UNK
@ SUMMON_CONTROL_TYPE_POSSESSED
@ SUMMON_TYPE_RUNEBLADE
@ SUMMON_TYPE_LIGHTWELL
@ SUMMON_TYPE_MINION
@ SUMMON_TYPE_GUARDIAN
@ SUMMON_TYPE_COMPANION
@ SUMMON_TYPE_PET
@ SUMMON_TYPE_TOTEM
@ SUMMON_TYPE_NONE
@ SUMMON_TYPE_OPPONENT
@ SUMMON_TYPE_VEHICLE
@ SUMMON_TYPE_CONSTRUCT
@ SUMMON_TYPE_MOUNT
void SpellEffectSummonGuardian(uint32_t i, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties_, LocationVector &v)
void SpellEffectSummonTemporaryPet(uint32_t i, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties_, LocationVector &v)
void spellEffectSummonTotem(uint8_t effectIndex, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties, LocationVector &v)
void SpellEffectSummonCompanion(uint32_t i, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties_, LocationVector &v)
void SpellEffectSummonWild(uint8_t effectIndex)
void SpellEffectSummonPossessed(uint32_t i, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties_, LocationVector &v)
void SpellEffectSummonVehicle(uint32_t i, WDB::Structures::SummonPropertiesEntry const *spe, CreatureProperties const *properties_, LocationVector &v)
Here is the call graph for this function:

◆ SpellEffectSummonCompanion()

void Spell::SpellEffectSummonCompanion ( uint32_t  i,
WDB::Structures::SummonPropertiesEntry const spe,
CreatureProperties const properties_,
LocationVector v 
)

Definition at line 3104 of file SpellEffects.Legacy.cpp.

3105{
3106 if (u_caster == nullptr)
3107 return;
3108
3109#if VERSION_STRING > TBC
3110 if (u_caster->getCritterGuid() != 0)
3111 {
3112 auto critter = u_caster->getWorldMap()->getUnit(u_caster->getCritterGuid());
3113 if (critter == nullptr)
3114 return;
3115
3116 auto creature = static_cast< Creature* >(critter);
3117
3118 uint32_t currententry = creature->GetCreatureProperties()->Id;
3119
3120 creature->RemoveFromWorld(false, true);
3121 u_caster->setCritterGuid(0);
3122
3123 // Before WOTLK when you casted the companion summon spell the second time it removed the companion
3124 // Customized servers or old databases could still use this method
3125 if (properties_->Id == currententry)
3126 return;
3127 }
3128
3129 auto summon = u_caster->getWorldMap()->summonCreature(properties_->Id, v, spe, static_cast<uint32_t>(getDuration()), u_caster, m_spellInfo->getId());
3130 if (summon == nullptr)
3131 return;
3132
3133 u_caster->setCritterGuid(summon->getGuid());
3134#endif
3135}
Summon * summonCreature(uint32_t entry, LocationVector pos, WDB::Structures::SummonPropertiesEntry const *=nullptr, uint32_t duration=0, Object *summoner=nullptr, uint32_t spellId=0)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ spellEffectSummonCompanion()

void Spell::spellEffectSummonCompanion ( uint8_t  effectIndex,
WDB::Structures::SummonPropertiesEntry const spe,
CreatureProperties const properties_,
LocationVector v 
)

◆ spellEffectSummonDeadPet()

void Spell::spellEffectSummonDeadPet ( uint8_t  effectIndex)

◆ SpellEffectSummonDeadPet()

void Spell::SpellEffectSummonDeadPet ( uint8_t  effectIndex)

Definition at line 5259 of file SpellEffects.Legacy.cpp.

5260{
5261 //this is pet resurrect
5262 if (!p_caster)
5263 return;
5264 Pet* pPet = p_caster->getPet();
5265 if (pPet)
5266 {
5267 // Pet should teleport to owner's position
5269 //\note remove all dynamic flags
5270 pPet->setDynamicFlags(0);
5271 pPet->setHealth(pPet->getMaxHealth() * damage / 100);
5272 pPet->setDeathState(ALIVE);
5273 pPet->getAIInterface()->handleEvent(EVENT_FOLLOWOWNER, pPet, 0);
5275
5276 // Restore unit and pvp flags that were resetted on death
5277 if (p_caster->isPvpFlagSet())
5278 pPet->setPvpFlag();
5279 else
5280 pPet->removePvpFlag();
5281
5283 pPet->setFfaPvpFlag();
5284 else
5285 pPet->removeFfaPvpFlag();
5286
5288 pPet->setSanctuaryFlag();
5289 else
5290 pPet->removeSanctuaryFlag();
5291
5294
5295#if VERSION_STRING == TBC
5298 else
5300#endif
5301 }
5302 else
5303 {
5304 // This was set in canCast so it should exist at this point
5305 if (add_damage == 0)
5306 return;
5307
5309 p_caster->spawnPet(static_cast<uint8_t>(add_damage));
5310
5311 pPet = p_caster->getPet();
5312 if (pPet == nullptr)//no pets to Revive
5313 return;
5314
5315 pPet->setHealth(pPet->getMaxHealth() * damage / 100);
5316 }
5317}
@ EVENT_FOLLOWOWNER
Definition AIEvents.h:22
@ POS_AURA_LIMIT_PVP_ATTACKABLE
@ POS_AURA_LIMIT_CREATURE
@ UNIT_FLAG_PVP_ATTACKABLE
void handleEvent(uint32_t event, Unit *pUnit, uint32_t misc1)
void setPvpFlag() override
Definition Creature.cpp:295
void removePvpFlag() override
Definition Creature.cpp:305
void setFfaPvpFlag() override
Definition Creature.cpp:324
void removeFfaPvpFlag() override
Definition Creature.cpp:332
void removeSanctuaryFlag() override
Definition Creature.cpp:357
void setSanctuaryFlag() override
Definition Creature.cpp:349
void sendSpellsToController(Unit *controller, uint32_t duration) override
Definition Pet.cpp:168
void setDeathState(DeathState s) override
Definition Pet.cpp:202
bool isSanctuaryFlagSet() const override
Definition Player.cpp:9852
bool isFfaPvpFlagSet() const override
Definition Player.cpp:9819
void spawnPet(uint8_t petId)
Definition Player.cpp:12538
bool isPetRequiringTemporaryUnsummon() const
Definition Player.cpp:12593
void HandleTeleport(LocationVector position, uint32_t mapid, Unit *Target)
uint32_t getTimeLeft() const
Definition Summon.cpp:269
void setPositiveAuraLimit(uint8_t limit)
Definition Unit.cpp:1553
Here is the call graph for this function:

◆ SpellEffectSummonGuardian()

void Spell::SpellEffectSummonGuardian ( uint32_t  i,
WDB::Structures::SummonPropertiesEntry const spe,
CreatureProperties const properties_,
LocationVector v 
)

Definition at line 3013 of file SpellEffects.Legacy.cpp.

3014{
3015 if (u_caster == nullptr)
3016 return;
3017
3018 float angle_for_each_spawn = -M_PI_FLOAT * 2 / damage;
3019
3020 for (int j = 0; j < damage; j++)
3021 {
3022 float followangle = angle_for_each_spawn * j;
3023
3024 float x = 3 * (cosf(followangle + u_caster->GetOrientation()));
3025 float y = 3 * (sinf(followangle + u_caster->GetOrientation()));
3026
3027 v.x += x;
3028 v.y += y;
3029
3030 Summon* s = u_caster->getWorldMap()->summonCreature(properties_->Id, v, spe, static_cast<uint32_t>(getDuration()), u_caster, getSpellInfo()->getId());
3031 if (s == nullptr)
3032 return;
3033
3034 // Lightwell
3035 if (spe->Type == SUMMON_TYPE_LIGHTWELL)
3036 {
3037 s->setMoveRoot(true);
3039 }
3040 }
3041}
@ UNIT_NPC_FLAG_SPELLCLICK
void addNpcFlags(uint64_t npcFlags)
Definition Unit.cpp:1441
Here is the call graph for this function:
Here is the caller graph for this function:

◆ spellEffectSummonGuardian()

void Spell::spellEffectSummonGuardian ( uint8_t  effectIndex,
WDB::Structures::SummonPropertiesEntry const spe,
CreatureProperties const properties_,
LocationVector v 
)

◆ spellEffectSummonObject()

void Spell::spellEffectSummonObject ( uint8_t  effectIndex)

◆ SpellEffectSummonObject()

void Spell::SpellEffectSummonObject ( uint8_t  effectIndex)

Definition at line 3930 of file SpellEffects.Legacy.cpp.

3931{
3932 if (!u_caster)
3933 return;
3934
3935 uint32_t entry = getSpellInfo()->getEffectMiscValue(effectIndex);
3936
3937 GameObjectProperties const* info = sMySQLStore.getGameObjectProperties(entry);
3938 if (info == nullptr)
3939 {
3940 sLogger.failure("Spell {} ( {} ) Effect Index {} tried to summon a GameObject with ID {}. GameObject is not in the database.", m_spellInfo->getId(), m_spellInfo->getName(), effectIndex, entry);
3941 return;
3942 }
3943
3945 float px = u_caster->GetPositionX();
3946 float py = u_caster->GetPositionY();
3947 float pz = u_caster->GetPositionZ();
3948
3949 int32_t duration = getDuration();
3950 GameObject* go = nullptr;
3951
3952 if (info->type == GAMEOBJECT_TYPE_FISHINGNODE)
3953 {
3954 if (p_caster == nullptr)
3955 return;
3956
3957 float minDist = m_spellInfo->getMinRange(true);
3958 float maxDist = m_spellInfo->getMaxRange(true);
3959 float posx = 0, posy = 0, posz = 0;
3960 float dist = Util::getRandomFloat(minDist, maxDist);
3961
3962 float angle = Util::getRandomFloat(0.0f, 1.0f) * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f);
3963 m_caster->getClosePoint(posx, posy, posz, 0.388999998569489f, dist, angle);
3964
3965 float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
3966
3967 LiquidData liquidData;
3968 if (map->getLiquidStatus(m_caster->GetPhase(), LocationVector(posx, posy, posz), MAP_ALL_LIQUIDS, &liquidData, m_caster->getCollisionHeight()))
3969 liquidLevel = liquidData.level;
3970
3971 go = u_caster->getWorldMap()->createGameObject(entry);
3972
3973 LocationVector pos = { posx, posy, liquidLevel, u_caster->GetOrientation() };
3975
3976 if (!go->create(entry, map, p_caster->GetPhase(), pos, rot, GO_STATE_CLOSED))
3977 {
3978 delete go;
3979 return;
3980 }
3981
3985
3987
3989 }
3990 else
3991 {
3992 float posx = px;
3993 float posy = py;
3994 auto destination = m_targets.getDestination();
3995
3996 if ((m_targets.hasDestination()) && destination.isSet())
3997 {
3998 posx = destination.x;
3999 posy = destination.y;
4000 pz = destination.z;
4001 }
4002
4003 LocationVector pos = { posx, posy, pz, u_caster->GetOrientation() };
4005 go = u_caster->getWorldMap()->createGameObject(entry);
4006 if (!go->create(entry, map, u_caster->GetPhase(), pos, rot, GO_STATE_CLOSED))
4007 {
4008 delete go;
4009 return;
4010 }
4011
4015 }
4016
4017 switch (info->type)
4018 {
4020 {
4024
4025 int32_t lastSec = 0;
4026 switch (Util::getRandomUInt(0, 2))
4027 {
4028 case 0: lastSec = 3; break;
4029 case 1: lastSec = 7; break;
4030 case 2: lastSec = 13; break;
4031 }
4032
4033 // Duration of the fishing bobber can't be higher than the Fishing channeling duration
4034 duration = std::min(duration, (duration - lastSec * IN_MILLISECONDS + 5 * IN_MILLISECONDS));
4035 } break;
4037 {
4038 if (u_caster->isPlayer())
4039 {
4042
4043 GameObject_Ritual* go_ritual = static_cast<GameObject_Ritual*>(go);
4044
4045 go_ritual->GetRitual()->Setup(p_caster->getGuidLow(), 0, m_spellInfo->getId());
4046 go_ritual->GetRitual()->Setup(p_caster->getGuidLow(), static_cast<uint32_t>(p_caster->getTargetGuid()), m_spellInfo->getId());
4047 }
4048 } break;
4049 case GAMEOBJECT_TYPE_DUEL_ARBITER: // 52991
4050 {
4053 } break;
4056 default:
4057 break;
4058 }
4059
4060 go->setRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0);
4062
4063 if (GameObject* linkedTrap = go->getLinkedTrap())
4064 {
4065 linkedTrap->setRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0);
4066 linkedTrap->setSpellId(m_spellInfo->getId());
4067 }
4068
4069 if (p_caster != nullptr)
4071}
@ GAMEOBJECT_TYPE_DUEL_ARBITER
@ GAMEOBJECT_TYPE_FISHINGNODE
@ GAMEOBJECT_TYPE_RITUAL
RitualStruct * GetRitual() const
Definition GameObject.h:634
bool create(uint32_t entry, WorldMap *map, uint32_t phase, LocationVector const &position, QuaternionData const &rotation, GameObject_State state, uint32_t spawnId=0)
void setRespawnTime(int32_t respawn)
void setSpellId(uint32_t id)
Definition GameObject.h:80
GameObject * getLinkedTrap()
void setGoType(uint8_t type)
void setCreatedByGuid(uint64_t guid)
void PushToWorld(WorldMap *)
Definition Object.cpp:3493
void addGameObject(GameObject *gameObj)
Definition Unit.cpp:8711
GameObject * createGameObject(uint32_t entry)
#define rot(x, k)
Definition lookup3.c:70
void Setup(uint64_t caster_guid, uint64_t target_guid, uint32_t spell_id)
Definition GameObject.h:557
static QuaternionData fromEulerAnglesZYX(float Z, float Y, float X)
Here is the call graph for this function:

◆ spellEffectSummonObjectSlot()

void Spell::spellEffectSummonObjectSlot ( uint8_t  effectIndex)

◆ SpellEffectSummonObjectSlot()

void Spell::SpellEffectSummonObjectSlot ( uint8_t  effectIndex)

Definition at line 5186 of file SpellEffects.Legacy.cpp.

5187{
5188 if (!u_caster || !u_caster->IsInWorld())
5189 return;
5190
5191 GameObject* GoSummon = nullptr;
5192
5195 u_caster->m_objectSlots[slot] = 0;
5196
5197 if (uint32_t guid = u_caster->m_objectSlots[slot])
5198 {
5199 if (GameObject* obj = u_caster->getWorldMapGameObject(guid))
5200 {
5201 // Recast case - null spell id to make auras not be removed on object remove from world
5202 if (m_spellInfo->getId() == obj->getSpellId())
5203 obj->setSpellId(0);
5204 u_caster->removeGameObject(obj, true);
5205 }
5206 u_caster->m_objectSlots[slot] = 0;
5207 }
5208
5209 // spawn a new one
5210 GoSummon = u_caster->getWorldMap()->createGameObject(getSpellInfo()->getEffectMiscValue(effectIndex));
5211
5212 float dx = 0.0f;
5213 float dy = 0.0f;
5214 float dz = 0.0f;
5215
5217 {
5218 auto destination = m_targets.getDestination();
5219 dx = destination.x;
5220 dy = destination.y;
5221 dz = destination.z;
5222 }
5223 else
5224 {
5225 dx = m_caster->GetPositionX();
5226 dy = m_caster->GetPositionY();
5227 dz = m_caster->GetPositionZ();
5228 }
5229
5231 if (!GoSummon->create(getSpellInfo()->getEffectMiscValue(effectIndex), m_caster->getWorldMap(), m_caster->GetPhase(), LocationVector(dx, dy, dz, m_caster->GetOrientation()), rot, GO_STATE_CLOSED))
5232 {
5233 delete GoSummon;
5234 return;
5235 }
5236
5237 GoSummon->setLevel(u_caster->getLevel());
5238 GoSummon->setCreatedByGuid(m_caster->getGuid());
5239 GoSummon->Phase(PHASE_SET, u_caster->GetPhase());
5240
5241 GoSummon->PushToWorld(m_caster->getWorldMap());
5242
5243 int32_t duration = getDuration();
5244
5245 GoSummon->setRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0);
5246 GoSummon->setSpellId(m_spellInfo->getId());
5247 u_caster->addGameObject(GoSummon);
5248 u_caster->m_objectSlots[slot] = GoSummon->GetUIdFromGUID();
5249}
@ PHASE_SET
@ SPELL_EFFECT_SUMMON_OBJECT_SLOT1
void setLevel(uint32_t level)
uint32_t GetUIdFromGUID() const
Definition Object.hpp:338
virtual void Phase(uint8_t command=PHASE_SET, uint32_t newphase=1)
Definition Object.cpp:4454
uint32_t m_objectSlots[4]
Definition Unit.hpp:1086
void removeGameObject(GameObject *gameObj, bool del)
Definition Unit.cpp:8720
Here is the call graph for this function:

◆ spellEffectSummonObjectWild()

void Spell::spellEffectSummonObjectWild ( uint8_t  effectIndex)

◆ SpellEffectSummonObjectWild()

void Spell::SpellEffectSummonObjectWild ( uint8_t  effectIndex)

Definition at line 4652 of file SpellEffects.Legacy.cpp.

4653{
4654 if (!u_caster)
4655 return;
4656
4657 uint32_t gameobject_id = getSpellInfo()->getEffectMiscValue(effectIndex);
4658
4659 float x, y, z;
4661 {
4663 }
4664 else
4665 {
4666 u_caster->getClosePoint(x, y, z, 0.388999998569489f);
4667 }
4668
4670
4672
4673 // spawn a new one
4674 GameObject* GoSummon = u_caster->getWorldMap()->createGameObject(gameobject_id);
4675 if (!GoSummon->create(gameobject_id, map, m_caster->GetPhase(), LocationVector(x, y, z, m_caster->GetOrientation()), rot, GO_STATE_CLOSED))
4676 {
4677 delete GoSummon;
4678 return;
4679 }
4680
4681 int32_t duration = getDuration();
4682
4683 GoSummon->setRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0);
4684
4685 GoSummon->PushToWorld(u_caster->getWorldMap());
4686 u_caster->addGameObject(GoSummon);
4687 GoSummon->setSpellId(m_spellInfo->getId());
4688
4689 if (GameObject* linkedTrap = GoSummon->getLinkedTrap())
4690 {
4691 linkedTrap->setRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0);
4692 linkedTrap->setSpellId(m_spellInfo->getId());
4693 }
4694}
void getPosition(float &rx, float &ry) const
Here is the call graph for this function:

◆ spellEffectSummonPet()

void Spell::spellEffectSummonPet ( uint8_t  effectIndex)

◆ SpellEffectSummonPet()

void Spell::SpellEffectSummonPet ( uint8_t  effectIndex)

Definition at line 4183 of file SpellEffects.Legacy.cpp.

4184{
4185 if (!p_caster) return;
4186
4187 if (getSpellInfo()->getId() == 883) // "Call Pet" spell
4188 {
4189 if (p_caster->getPet() != nullptr)
4190 {
4192 return;
4193 }
4194
4195 const auto foundPetId = p_caster->getPetIdFromSlot(PET_SLOT_FIRST_ACTIVE_SLOT);
4196 if (foundPetId.has_value())
4197 {
4198 const auto petno = foundPetId.value();
4200 {
4201#if VERSION_STRING < WotLK
4203#else
4204 sendCastResult(SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW);
4205#endif
4206 return;
4207 }
4208
4209 if (p_caster->getPetCache(petno) == nullptr)
4210 {
4212 return;
4213 }
4214
4215 if (p_caster->getPetCache(petno)->alive)
4216 {
4217 p_caster->spawnPet(petno);
4218 }
4219 else
4220 {
4222 }
4223 }
4224 else
4225 {
4227 }
4228 return;
4229 }
4230
4231 //uint32_t entryId = GetProto()->EffectMiscValue[i];
4232
4233 //VoidWalker:torment, sacrifice, suffering, consume shadows
4234 //Succubus:lash of pain, soothing kiss, seduce , lesser invisibility
4235 //felhunter: Devour Magic,Paranoia,Spell Lock, Tainted Blood
4236
4237 // remove old pet
4238 Pet* old = p_caster->getPet();
4239 if (old)
4240 old->unSummon();
4241
4242 CreatureProperties const* ci = sMySQLStore.getCreatureProperties(getSpellInfo()->getEffectMiscValue(effectIndex));
4243 if (ci)
4244 {
4245 if (p_caster->getClass() == WARLOCK)
4246 {
4247 //if demonic sacrifice auras are still active, remove them
4253 }
4254
4255 const auto pet = sObjectMgr.createPet(getSpellInfo()->getEffectMiscValue(effectIndex), nullptr);
4256 if (!pet->createAsSummon(ci, nullptr, u_caster, u_caster->GetPosition(), 0, m_spellInfo, effectIndex, PET_TYPE_SUMMON))
4257 {
4258 pet->DeleteMe();//CreateAsSummon() returns false if an error occurred.
4259 }
4260 }
4261}
@ PET_TYPE_SUMMON
@ PET_SLOT_FIRST_ACTIVE_SLOT
@ WARLOCK
std::optional< uint8_t > getPetIdFromSlot(uint8_t slot) const
Definition Player.cpp:12335
Here is the call graph for this function:

◆ spellEffectSummonPlayer()

void Spell::spellEffectSummonPlayer ( uint8_t  effectIndex)

◆ SpellEffectSummonPlayer()

void Spell::SpellEffectSummonPlayer ( uint8_t  effectIndex)

Definition at line 4782 of file SpellEffects.Legacy.cpp.

4783{
4784 if (!m_playerTarget)
4785 return;
4786
4787 // vojta: from 2.4 players can be summoned on another map
4788 //if (m_caster->getWorldMap()->GetMapInfo() && m_caster->getWorldMap()->GetMapInfo()->type != INSTANCE_NULL && m_caster->GetMapId() != playerTarget->GetMapId())
4789 // return;
4790 if (m_caster->getWorldMap()->getBaseMap()->getMapInfo() && m_playerTarget->getLevel() < m_caster->getWorldMap()->getBaseMap()->getMapInfo()->minlevel) // we need some blizzlike message that player needs level xx - feel free to add it ;)
4791 return;
4792
4794}
void sendSummonRequest(uint32_t requesterId, uint32_t zoneId, uint32_t mapId, uint32_t instanceId, const LocationVector &position)
Definition Player.cpp:2386
Here is the call graph for this function:

◆ SpellEffectSummonPossessed()

void Spell::SpellEffectSummonPossessed ( uint32_t  i,
WDB::Structures::SummonPropertiesEntry const spe,
CreatureProperties const properties_,
LocationVector v 
)

Definition at line 3086 of file SpellEffects.Legacy.cpp.

3087{
3088 if (p_caster == nullptr)
3089 return;
3090
3091 if (p_caster->getPet() != nullptr)
3092 p_caster->getPet()->unSummon();
3093
3094 v.x += (3 * cos(M_PI_FLOAT / 2 + v.o));
3095 v.y += (3 * cos(M_PI_FLOAT / 2 + v.o));
3096
3097 Summon* s = p_caster->getWorldMap()->summonCreature(properties_->Id, v, spe, static_cast<uint32_t>(getDuration()), p_caster, m_spellInfo->getId());
3098 if (s == nullptr)
3099 return;
3100
3101 p_caster->possess(s, 1000);
3102}
void possess(Unit *unitTarget, uint32_t delay=0)
Definition Unit.cpp:8946
Here is the call graph for this function:
Here is the caller graph for this function:

◆ spellEffectSummonPossessed()

void Spell::spellEffectSummonPossessed ( uint8_t  effectIndex,
WDB::Structures::SummonPropertiesEntry const spe,
CreatureProperties const properties_,
LocationVector v 
)

◆ SpellEffectSummonTemporaryPet()

void Spell::SpellEffectSummonTemporaryPet ( uint32_t  i,
WDB::Structures::SummonPropertiesEntry const spe,
CreatureProperties const properties_,
LocationVector v 
)

Definition at line 3043 of file SpellEffects.Legacy.cpp.

3044{
3045 if (p_caster == nullptr)
3046 return;
3047
3048 if (p_caster->getPet() != nullptr)
3049 p_caster->getPet()->unSummon();
3050
3051 int32_t count = 0;
3052
3053 // Only Inferno uses this SummonProperty ID, and somehow it has the wrong count
3054 if (spe->ID == 711)
3055 count = 1;
3056 else
3057 count = damage;
3058
3059 // We know for sure that this will suceed because we checked in Spell::SpellEffectSummon
3060 CreatureProperties const* ci = sMySQLStore.getCreatureProperties(properties_->Id);
3061
3062 float angle_for_each_spawn = -M_PI_FLOAT * 2 / damage;
3063
3064 for (int32_t i = 0; i < count; i++)
3065 {
3066 float followangle = angle_for_each_spawn * i;
3067
3068 float x = 3 * (cosf(followangle + u_caster->GetOrientation()));
3069 float y = 3 * (sinf(followangle + u_caster->GetOrientation()));
3070
3071 v.x += x;
3072 v.y += y;
3073
3074 const auto pet = sObjectMgr.createPet(properties_->Id, spe);
3075 if (!pet->createAsSummon(ci, nullptr, p_caster, v, static_cast<uint32_t>(getDuration()), m_spellInfo, i, PET_TYPE_SUMMON))
3076 {
3077 pet->DeleteMe();
3078 break;
3079 }
3080
3081 // Delay this a bit to make sure its Spawned
3083 }
3084}
@ EVENT_UNK
Definition EventMgr.h:30
void InitSummon(Object *summoner)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ spellEffectSummonTemporaryPet()

void Spell::spellEffectSummonTemporaryPet ( uint8_t  effectIndex,
WDB::Structures::SummonPropertiesEntry const spe,
CreatureProperties const properties_,
LocationVector v 
)

◆ spellEffectSummonTotem()

void Spell::spellEffectSummonTotem ( uint8_t  effectIndex,
WDB::Structures::SummonPropertiesEntry const spe,
CreatureProperties const properties,
LocationVector v 
)

Definition at line 525 of file SpellEffects.Legacy.cpp.

526{
527 if (u_caster == nullptr)
528 return;
529
530 const auto totemSlot = static_cast<SummonSlot>(spe->Slot);
531
532 // Generate spawn point
533 const float_t angle = totemSlot > SUMMON_SLOT_NONE && totemSlot < SUMMON_SLOT_MINIPET
534 ? M_PI_FLOAT / static_cast<float>(SUMMON_SLOT_TOTEM_AIR) - (totemSlot * 2 * M_PI_FLOAT / static_cast<float>(SUMMON_SLOT_TOTEM_AIR))
535 : 0.0f;
536 u_caster->GetPoint(u_caster->GetOrientation() + angle, 3.5f, v.x, v.y, v.z, false);
537
538 // Correct Z position
539 //\ todo: this probably should be inside Object::GetPoint()
540 const auto landHeight = u_caster->getWorldMap()->getHeight(LocationVector(v.x, v.y, v.z + 2));
541 const auto landDiff = landHeight - v.z;
542 if (fabs(landDiff) <= 15)
543 v.z = landHeight;
544
545 auto summonDuration = static_cast<uint32_t>(getDuration());
546 if (summonDuration == 0)
547 summonDuration = 10 * 60 * 1000; // 10 min if duration does not exist
548
549 // Create totem
550 const auto totem = u_caster->getWorldMap()->summonCreature(properties->Id, v, spe, summonDuration, u_caster, getSpellInfo()->getId());
551 if (totem == nullptr)
552 return;
553
554 totem->setMaxHealth(damage);
555 totem->setHealth(damage);
556}
@ SUMMON_SLOT_NONE
@ SUMMON_SLOT_MINIPET
void setMaxHealth(uint32_t maxHealth)
Definition Unit.cpp:626
float getHeight(LocationVector const &pos, bool vmap=true, float maxSearchDist=50.0f) const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SpellEffectSummonVehicle()

void Spell::SpellEffectSummonVehicle ( uint32_t  i,
WDB::Structures::SummonPropertiesEntry const spe,
CreatureProperties const properties_,
LocationVector v 
)

Definition at line 3137 of file SpellEffects.Legacy.cpp.

3138{
3139 if (u_caster == nullptr)
3140 return;
3141
3142 // If it has no vehicle id, then we can't really do anything with it as a vehicle :/
3143 if ((properties_->vehicleid == 0) && (p_caster == nullptr))
3144 return;
3145
3146 Creature* c = u_caster->getWorldMap()->createCreature(properties_->Id);
3147 c->Load(properties_, v.x, v.y, v.z, v.o);
3154
3155 // Delay this a bit to make sure its Spawned
3157
3158#ifdef FT_VEHICLES
3159 // Need to delay this a bit since first the client needs to see the vehicle
3160 u_caster->callEnterVehicle(c);
3161#endif
3162}
bool Load(MySQLStructure::CreatureSpawn *spawn, uint8_t mode, MySQLStructure::MapInfo const *info)
void setSummonedByGuid(uint64_t guid)
Definition Unit.cpp:395
virtual void setPhase(uint8_t command=PHASE_SET, uint32_t newPhase=1)
Definition Unit.cpp:1715
void setCreatedBySpellId(uint32_t id)
Definition Unit.cpp:1431
void setCreatedByGuid(uint64_t guid)
Definition Unit.cpp:398
void removeNpcFlags(uint64_t npcFlags)
Definition Unit.cpp:1442
Creature * createCreature(uint32_t entry)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ spellEffectSummonVehicle()

void Spell::spellEffectSummonVehicle ( uint8_t  effectIndex,
WDB::Structures::SummonPropertiesEntry const spe,
CreatureProperties const properties_,
LocationVector v 
)

◆ spellEffectSummonWild()

void Spell::spellEffectSummonWild ( uint8_t  effectIndex)

◆ SpellEffectSummonWild()

void Spell::SpellEffectSummonWild ( uint8_t  effectIndex)

Definition at line 2941 of file SpellEffects.Legacy.cpp.

2942{
2943 //these are some creatures that have your faction and do not respawn
2944 //number of creatures is actually dmg (the usual formula), sometimes =3 sometimes =1
2945 //if( u_caster == NULL || !u_caster->IsInWorld() )
2946 // return;
2947
2949 return;
2950
2951 uint32_t cr_entry = getSpellInfo()->getEffectMiscValue(effectIndex);
2952 CreatureProperties const* properties = sMySQLStore.getCreatureProperties(cr_entry);
2953 if (properties == nullptr)
2954 {
2955 sLogger.failure("Warning : Missing summon creature template {} used by spell {}!", cr_entry, getSpellInfo()->getId());
2956 return;
2957 }
2958 float x, y, z;
2960 {
2961 auto destination = m_targets.getDestination();
2962 x = destination.x;
2963 y = destination.y;
2964 z = destination.z;
2965 }
2966 else
2967 {
2968 x = m_caster->GetPositionX();
2969 y = m_caster->GetPositionY();
2970 z = m_caster->GetPositionZ();
2971 }
2972 for (int j = 0; j<damage; j++)
2973 {
2974 float m_fallowAngle = -((float(M_PI) / 2) * j);
2975 float tempx = x + (getEffectRadius(effectIndex) * (cosf(m_fallowAngle + m_caster->GetOrientation())));
2976 float tempy = y + (getEffectRadius(effectIndex) * (sinf(m_fallowAngle + m_caster->GetOrientation())));
2977
2978 if (Creature* p = m_caster->getWorldMap()->createCreature(cr_entry))
2979 {
2980 p->Load(properties, tempx, tempy, z);
2981 p->setZoneId(m_caster->getZoneId());
2982
2983 if (p->GetCreatureProperties()->Faction == 35)
2984 {
2985 if (m_caster->isGameObject())
2986 p->setFaction(static_cast<GameObject*>(m_caster)->getFactionTemplate());
2987 else
2988 p->setFaction(static_cast<Unit*>(m_caster)->getFactionTemplate());
2989 }
2990 else
2991 {
2992 p->setFaction(properties->Faction);
2993 }
2994
2995 p->setSummonedByGuid(m_caster->getGuid());
2996 p->setCreatedByGuid(m_caster->getGuid());
2997
2998 p->PushToWorld(m_caster->getWorldMap());
2999
3000 // Delay this a bit to make sure its Spawned
3002
3003 //make sure they will be desummoned (roxor)
3005 }
3006 else
3007 {
3008 sLogger.failure("Spell::SpellEffectSummonWild tried to summon invalid creature {}", cr_entry);
3009 }
3010 }
3011}
@ EVENT_SUMMON_EXPIRE
Definition EventMgr.h:63
void SummonExpire()
Definition Creature.h:203
Here is the call graph for this function:
Here is the caller graph for this function:

◆ spellEffectTameCreature()

void Spell::spellEffectTameCreature ( uint8_t  effectIndex)

◆ SpellEffectTameCreature()

void Spell::SpellEffectTameCreature ( uint8_t  effectIndex)

Definition at line 4165 of file SpellEffects.Legacy.cpp.

4166{
4167 if (m_unitTarget == nullptr || !m_unitTarget->isCreature())
4168 return;
4169 if (p_caster == nullptr || p_caster->getPet() != nullptr)
4170 return;
4171 Creature* tame = static_cast<Creature*>(m_unitTarget);
4172
4173 // Remove target
4175 const auto pet = sObjectMgr.createPet(tame->getEntry(), nullptr);
4176 if (!pet->createAsSummon(tame->GetCreatureProperties(), tame, p_caster, p_caster->GetPosition(), 0, nullptr, effectIndex, PET_TYPE_HUNTER))
4177 {
4178 pet->DeleteMe();//CreateAsSummon() returns false if an error occurred.
4179 }
4180 tame->Despawn(0, tame->GetCreatureProperties()->RespawnTime);
4181}
@ EVENT_LEAVECOMBAT
Definition AIEvents.h:18
Here is the call graph for this function:

◆ spellEffectTeachTaxiPath()

void Spell::spellEffectTeachTaxiPath ( uint8_t  effectIndex)

◆ SpellEffectTeachTaxiPath()

void Spell::SpellEffectTeachTaxiPath ( uint8_t  effectIndex)

Definition at line 6060 of file SpellEffects.Legacy.cpp.

6061{
6062 if (!m_playerTarget || !getSpellInfo()->getEffectTriggerSpell(effectIndex))
6063 return;
6064
6065 uint32_t nodeid = m_spellInfo->getEffectMiscValue(effectIndex);
6066 if (sTaxiNodesStore.lookupEntry(nodeid))
6067 {
6069 }
6070}
SERVER_DECL WDB::WDBContainer< WDB::Structures::TaxiNodesEntry > sTaxiNodesStore
void sendDiscoverNewTaxiNode(uint32_t nodeid)
Here is the call graph for this function:

◆ spellEffectTeleportUnits()

void Spell::spellEffectTeleportUnits ( uint8_t  effectIndex)

◆ SpellEffectTeleportUnits()

void Spell::SpellEffectTeleportUnits ( uint8_t  effectIndex)

Definition at line 1717 of file SpellEffects.Legacy.cpp.

1718{
1719 if (m_unitTarget == nullptr || m_caster == nullptr)
1720 return;
1721
1722 uint32_t spellId = getSpellInfo()->getId();
1723
1724 // Portals
1726 {
1727 TeleportCoords const* teleport_coord = sMySQLStore.getTeleportCoord(spellId);
1728 if (teleport_coord == nullptr)
1729 {
1730 sLogger.failure("Spell {} ({}) has a TELEPORT TO COORDINATES effect, but has no coordinates to teleport to. ", spellId, m_spellInfo->getName());
1731 return;
1732 }
1733
1734 HandleTeleport(LocationVector(teleport_coord->x, teleport_coord->y, teleport_coord->z), teleport_coord->mapId, m_unitTarget);
1735 return;
1736 }
1737
1738 // Hearthstone and co.
1740 {
1741 if (m_unitTarget->isPlayer())
1742 {
1743 Player* p = static_cast<Player*>(m_unitTarget);
1744
1746 }
1747 return;
1748 }
1749
1750 // Summon
1752 {
1753 if (u_caster == nullptr)
1754 return;
1755
1757 return;
1758 }
1759
1760 // Shadowstep for example
1762 {
1763 if (p_caster == nullptr)
1764 return;
1765
1766 ///////////////////////////////////////////////// Code taken from the Shadowstep dummy script /////////////////////////////////////////////////////////////////////
1767
1768 /* this is rather tricky actually. we have to calculate the orientation of the creature/player, and then calculate a little bit of distance behind that. */
1769 float ang;
1770
1771 if (m_unitTarget == m_caster)
1772 {
1773 /* try to get a selection */
1776 {
1777 return;
1778 }
1779 }
1780
1781 if (m_unitTarget->isCreature())
1782 {
1783 if (m_unitTarget->getTargetGuid() != 0)
1784 {
1785 /* We're chasing a target. We have to calculate the angle to this target, this is our orientation. */
1787 /* convert degree angle to radians */
1788 ang = ang * M_PI_FLOAT / 180.0f;
1789 }
1790 else
1791 {
1792 /* Our orientation has already been set. */
1794 }
1795 }
1796 else
1797 {
1798 /* Players orientation is sent in movement packets */
1800 }
1801 // avoid teleporting into the model on scaled models
1802 const static float shadowstep_distance = 1.6f * m_unitTarget->getScale();
1803 float new_x = m_unitTarget->GetPositionX() - (shadowstep_distance * cosf(ang));
1804 float new_y = m_unitTarget->GetPositionY() - (shadowstep_distance * sinf(ang));
1805 /* Send a movement packet to "charge" at this target. Similar to warrior charge. */
1806 p_caster->m_zAxisPosition = 0.0f;
1808
1809
1810 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1811
1812 return;
1813 }
1814
1815 // For those special teleport spells
1816 if (sScriptMgr.CallScriptedDummySpell(m_spellInfo->getId(), effectIndex, this))
1817 return;
1818
1819 sLogger.failure("Unhandled Teleport effect Index %hhu for Spell {} ({}).", effectIndex, m_spellInfo->getId(), m_spellInfo->getName());
1820}
float getScale() const
Definition Object.cpp:407
float calcAngle(float Position1X, float Position1Y, float Position2X, float Position2Y)
Definition Object.cpp:3660
bool hasCustomFlagForEffect(uint32_t effectIndex, uint32_t flag) const
float m_zAxisPosition
Definition Unit.hpp:612
Here is the call graph for this function:

◆ spellEffectThreat()

void Spell::spellEffectThreat ( uint8_t  effectIndex)

◆ SpellEffectThreat()

void Spell::SpellEffectThreat ( uint8_t  effectIndex)

Definition at line 4382 of file SpellEffects.Legacy.cpp.

4383{
4385 return;
4386
4387 int32_t amount = getSpellInfo()->getEffectBasePoints(effectIndex);
4388
4390
4391 if (!chck)
4392 {
4395 }
4396 else
4398}
Here is the call graph for this function:

◆ spellEffectTransformItem()

void Spell::spellEffectTransformItem ( uint8_t  effectIndex)

◆ SpellEffectTransformItem()

void Spell::SpellEffectTransformItem ( uint8_t  effectIndex)

Definition at line 3620 of file SpellEffects.Legacy.cpp.

3621{
3622 bool result;
3623
3624 if (!i_caster) return;
3625 uint32_t itemid = getSpellInfo()->getEffectItemType(effectIndex);
3626 if (!itemid) return;
3627
3628 //Save durability of the old item
3629 Player* owner = i_caster->getOwner();
3631
3633 if (!result)
3634 {
3635 //something went wrong if this happen, item doesn't exist, so it wasn't destroyed.
3636 return;
3637 }
3638
3639 i_caster = nullptr;
3640
3641 auto it = sObjectMgr.createItem(itemid, owner);
3642 if (!it) return;
3643
3644 it->setDurability(dur);
3645 //additem
3646
3647 //additem
3648 const auto [result2, _] = owner->getItemInterface()->AddItemToFreeSlot(std::move(it));
3649 if (!result2) //should never get here
3650 {
3651 owner->getItemInterface()->buildInventoryChangeError(nullptr, nullptr, INV_ERR_BAG_FULL);
3652 }
3653}
@ INV_ERR_BAG_FULL
Here is the call graph for this function:

◆ spellEffectTriggerMissile()

void Spell::spellEffectTriggerMissile ( uint8_t  effectIndex)

◆ SpellEffectTriggerMissile()

void Spell::SpellEffectTriggerMissile ( uint8_t  effectIndex)

Definition at line 3337 of file SpellEffects.Legacy.cpp.

3338{
3339 //Used by mortar team
3340 //Triggers area effect spell at destinatiom
3341
3342 uint32_t spellid = getSpellInfo()->getEffectTriggerSpell(effectIndex);
3343 if (spellid == 0)
3344 {
3345 sLogger.failure("Spell {} ({}) has a trigger missle effect index (%hhu) but no trigger spell ID. Spell needs fixing.", m_spellInfo->getId(), m_spellInfo->getName(), effectIndex);
3346 return;
3347 }
3348
3349 SpellInfo const* spInfo = sSpellMgr.getSpellInfo(spellid);
3350 if (spInfo == nullptr)
3351 {
3352 sLogger.failure("Spell {} ({}) has a trigger missle effect index (%hhu) but has an invalid trigger spell ID. Spell needs fixing.", m_spellInfo->getId(), m_spellInfo->getName(), effectIndex);
3353 return;
3354 }
3355
3356 // Cast the triggered spell on the destination location, spells like Freezing Arrow use it
3357 if ((u_caster != nullptr) && (m_targets.hasDestination()))
3358 {
3360 return;
3361 }
3362
3363 float spellRadius = getEffectRadius(effectIndex);
3364
3365 //\todo Following should be / is probably in SpellTarget code
3366 for (const auto& itr : m_caster->getInRangeObjectsSet())
3367 {
3368 if (!itr || !itr->isCreatureOrPlayer() || !static_cast<Unit*>(itr)->isAlive())
3369 continue;
3370
3371 Unit* t = static_cast<Unit*>(itr);
3372
3373 float r;
3374 auto destination = m_targets.getDestination();
3375 float d = destination.x - t->GetPositionX();
3376 r = d * d;
3377 d = destination.y - t->GetPositionY();
3378 r += d * d;
3379 d = destination.z - t->GetPositionZ();
3380 r += d * d;
3381
3382 if (std::sqrt(r) > spellRadius) continue;
3383
3384 if (!m_caster->isValidTarget(itr)) //Fix Me: only enemy targets?
3385 continue;
3386
3387 Spell* sp = sSpellMgr.newSpell(m_caster, spInfo, true, nullptr);
3388 SpellCastTargets tgt(itr->getGuid());
3389 sp->prepare(&tgt);
3390 }
3391}
SpellCastResult castSpellLoc(const LocationVector location, uint32_t spellId, bool triggered=false)
Definition Unit.cpp:3649
Here is the call graph for this function:

◆ spellEffectTriggerSpell()

void Spell::spellEffectTriggerSpell ( uint8_t  effectIndex)

Definition at line 630 of file SpellEffects.Legacy.cpp.

631{
632 const auto triggerInfo = sSpellMgr.getSpellInfo(getSpellInfo()->getEffectTriggerSpell(effectIndex));
633 if (triggerInfo == nullptr)
634 return;
635
636 SpellCastTargets targets = m_targets;
637 Spell* triggerSpell = sSpellMgr.newSpell(m_caster, triggerInfo, true, nullptr);
638 triggerSpell->ProcedOnSpell = getSpellInfo();
639 triggerSpell->prepare(&targets);
640}
Here is the call graph for this function:

◆ spellEffectTriggerSpellWithValue()

void Spell::spellEffectTriggerSpellWithValue ( uint8_t  effectIndex)

◆ SpellEffectTriggerSpellWithValue()

void Spell::SpellEffectTriggerSpellWithValue ( uint8_t  effectIndex)

Definition at line 6013 of file SpellEffects.Legacy.cpp.

6014{
6015 if (!m_unitTarget) return;
6016
6017 SpellInfo const* TriggeredSpell = sSpellMgr.getSpellInfo(getSpellInfo()->getEffectTriggerSpell(effectIndex));
6018 if (TriggeredSpell == nullptr)
6019 return;
6020
6021 Spell* sp = sSpellMgr.newSpell(m_caster, TriggeredSpell, true, nullptr);
6022
6023 for (uint8_t x = 0; x < 3; x++)
6024 {
6025 if (effectIndex == x)
6026 sp->forced_basepoints->set(x, damage); //prayer of mending should inherit heal bonus ?
6027 else
6028 sp->forced_basepoints->set(x, TriggeredSpell->getEffectBasePoints(effectIndex));
6029
6030 }
6031
6033 sp->prepare(&tgt);
6034}
Here is the call graph for this function:

◆ spellEffectUseGlyph()

void Spell::spellEffectUseGlyph ( uint8_t  effectIndex)

◆ SpellEffectUseGlyph()

void Spell::SpellEffectUseGlyph ( uint8_t  effectIndex)

Definition at line 4590 of file SpellEffects.Legacy.cpp.

4591{
4592#if VERSION_STRING > TBC
4593 if (!p_caster)
4594 return;
4595
4597 return;
4598
4599 const auto glyphSlot = static_cast<uint16_t>(m_glyphslot);
4600 uint32_t glyph_new = m_spellInfo->getEffectMiscValue(effectIndex);
4601 auto glyph_prop_new = sGlyphPropertiesStore.lookupEntry(glyph_new);
4602 if (!glyph_prop_new)
4603 return;
4604
4605 // check if glyph is locked (obviously)
4606 if (!(p_caster->getGlyphsEnabled() & (1 << glyphSlot)))
4607 {
4608 sendCastResult(SPELL_FAILED_GLYPH_SOCKET_LOCKED);
4609 return;
4610 }
4611
4612 uint32_t glyph_old = p_caster->getGlyph(glyphSlot);
4613 if (glyph_old)
4614 {
4615 if (glyph_old == glyph_new)
4616 {
4617 return;
4618 }
4619 else
4620 {
4621 auto glyph_prop_old = sGlyphPropertiesStore.lookupEntry(glyph_old);
4622 if (glyph_prop_old)
4623 p_caster->removeAllAurasById(glyph_prop_old->SpellID);
4624 }
4625 }
4626
4627 auto glyph_slot = sGlyphSlotStore.lookupEntry(p_caster->getGlyphSlot(glyphSlot));
4628 if (glyph_slot)
4629 {
4630 if (glyph_slot->Type != glyph_prop_new->Type)
4631 {
4632 sendCastResult(SPELL_FAILED_INVALID_GLYPH);
4633 return;
4634 }
4635 p_caster->setGlyph(glyphSlot, glyph_new);
4636 p_caster->castSpell(p_caster, glyph_prop_new->SpellID, true);
4637 p_caster->m_specs[p_caster->m_talentActiveSpec].setGlyph(static_cast<uint16_t>(glyph_new), glyphSlot);
4638 p_caster->smsg_TalentsInfo(false);
4639 }
4640#endif
4641}
#define GLYPHS_COUNT
SERVER_DECL WDB::WDBContainer< WDB::Structures::GlyphSlotEntry > sGlyphSlotStore
void setGlyph(uint16_t slot, uint32_t glyph)
Definition Player.cpp:1310
uint32_t getGlyph(uint16_t slot) const
Definition Player.cpp:1309
uint32_t getGlyphSlot(uint16_t slot) const
Definition Player.cpp:1306
Here is the call graph for this function:

◆ spellEffectWeapon()

void Spell::spellEffectWeapon ( uint8_t  effectIndex)

Definition at line 558 of file SpellEffects.Legacy.cpp.

559{
560 if (m_playerTarget == nullptr)
561 return;
562
563 uint16_t skillId = 0;
564 const auto skillLineAbility = sSpellMgr.getFirstSkillEntryForSpell(getSpellInfo()->getId());
565 if (skillLineAbility != nullptr)
566 skillId = static_cast<uint16_t>(skillLineAbility->skilline);
567
568 const auto skillLine = sSkillLineStore.lookupEntry(skillId);
569 if (skillLine == nullptr)
570 return;
571
572 if (!m_playerTarget->hasSkillLine(skillId))
573 m_playerTarget->addSkillLine(skillId, 1, 0);
574}
Here is the call graph for this function:

◆ spellEffectWeapondamage()

void Spell::spellEffectWeapondamage ( uint8_t  effectIndex)

◆ SpellEffectWeapondamage()

void Spell::SpellEffectWeapondamage ( uint8_t  effectIndex)

Definition at line 4288 of file SpellEffects.Legacy.cpp.

4289{
4290 if (!m_unitTarget || !u_caster)
4291 return;
4292
4293 //Hackfix for Mangle
4294 if (p_caster != nullptr)
4295 {
4296 switch (getSpellInfo()->getId())
4297 {
4298 case 33876:
4299 case 33982:
4300 case 33983:
4301 case 48565:
4302 case 48566:
4304 break;
4305 }
4306 }
4307
4308 // Hacky fix for druid spells where it would "double attack".
4310 {
4311 add_damage += damage;
4312 return;
4313 }
4314
4315 WeaponDamageType _type;
4317 _type = RANGED;
4318 else
4319 {
4321 _type = OFFHAND;
4322 else
4323 _type = MELEE;
4324 }
4326 isTargetDamageInfoSet = true;
4327}
Here is the call graph for this function:

◆ spellEffectWeapondamageNoschool()

void Spell::spellEffectWeapondamageNoschool ( uint8_t  effectIndex)

◆ SpellEffectWeapondamageNoschool()

void Spell::SpellEffectWeapondamageNoschool ( uint8_t  effectIndex)

Definition at line 2411 of file SpellEffects.Legacy.cpp.

2412{
2413 if (!m_unitTarget || !u_caster)
2414 return;
2415
2417 isTargetDamageInfoSet = true;
2418}
Here is the call graph for this function:

◆ spellEffectWeaponDmgPerc()

void Spell::spellEffectWeaponDmgPerc ( uint8_t  effectIndex)

◆ SpellEffectWeaponDmgPerc()

void Spell::SpellEffectWeaponDmgPerc ( uint8_t  effectIndex)

Definition at line 3263 of file SpellEffects.Legacy.cpp.

3264{
3265 if (!m_unitTarget || !u_caster) return;
3266
3268 {
3269 auto dmg = CalculateDamage(u_caster, m_unitTarget, MELEE, nullptr, getSpellInfo()) * damage / 100.0f;
3270
3271 // Get bonus damage from spell power and attack power
3272 if (!isEffectDamageStatic[effectIndex])
3273 dmg = getUnitCaster()->applySpellDamageBonus(getSpellInfo(), static_cast<int32_t>(dmg), effectPctModifier[effectIndex], false, this);
3274
3275 m_targetDamageInfo = u_caster->doSpellDamage(m_unitTarget, getSpellInfo()->getId(), dmg, effectIndex, m_triggeredSpell, false, false, isForcedCrit, this);
3276 isTargetDamageInfoSet = true;
3277 }
3278 else
3279 {
3280 WeaponDamageType _type;
3282 _type = RANGED;
3283 else
3284 {
3285 if (getSpellInfo()->getAttributesExC() & ATTRIBUTESEXC_REQUIRES_OFFHAND_WEAPON)
3286 _type = OFFHAND;
3287 else
3288 _type = MELEE;
3289 }
3290
3292 isTargetDamageInfoSet = true;
3293
3294 if (p_caster != nullptr) // rogue - fan of knives
3295 {
3296 switch (getSpellInfo()->getId())
3297 {
3298 // SPELL_HASH_FAN_OF_KNIVES
3299 case 51723:
3300 case 52874:
3301 case 61739:
3302 case 61740:
3303 case 61741:
3304 case 61742:
3305 case 61743:
3306 case 61744:
3307 case 61745:
3308 case 61746:
3309 case 63753:
3310 case 65955:
3311 case 67706:
3312 case 68097:
3313 case 68098:
3314 case 68099:
3315 case 69921:
3316 case 71128:
3317 {
3319 if (oit != nullptr)
3320 {
3321 if (oit->getDurability() != 0)
3322 {
3323 if (oit->getItemProperties()->Class == 2 && oit->getItemProperties()->SubClass == 15) // daggers
3324 damage = 105; //causing 105% weapon damage with daggers
3325 else
3326 damage = getSpellInfo()->getEffectBasePoints(effectIndex) + 1;// and 70% weapon damage with all other weapons.
3327
3329 }
3330 }
3331 } break;
3332 }
3333 }
3334 }
3335}
uint32_t CalculateDamage(Unit *pAttacker, Unit *pVictim, uint32_t weapon_damage_type, const uint32_t *, SpellInfo const *ability)
Definition Stats.cpp:626
float_t applySpellDamageBonus(SpellInfo const *spellInfo, int32_t baseDmg, float_t effectPctModifier=1.0f, bool isPeriodic=false, Spell *castingSpell=nullptr, Aura *aur=nullptr)
Definition Unit.cpp:3913
Here is the call graph for this function:

◆ takePower()

void Spell::takePower ( )
private

Definition at line 5557 of file Spell.cpp.

5558{
5559 // Items do not use caster's power and only units have power
5560 if (i_caster != nullptr || u_caster == nullptr || m_triggeredByAura != nullptr)
5561 return;
5562
5563 if (p_caster != nullptr && p_caster->m_cheats.hasPowerCheat)
5564 return;
5565
5566 if (getSpellInfo()->getPowerType() == POWER_TYPE_HEALTH)
5567 {
5568 //\ todo: is this correct order?
5570 u_caster->dealDamage(u_caster, getPowerCost(), getSpellInfo()->getId(), false);
5571 return;
5572 }
5573#if VERSION_STRING >= WotLK
5574 else if (getSpellInfo()->getPowerType() == POWER_TYPE_RUNES)
5575 {
5576 checkRunes(true);
5577 return;
5578 }
5579#endif
5580 else if (getSpellInfo()->getPowerType() == POWER_TYPE_MANA && m_powerCost > 0)
5581 {
5582 // Start five second timer later at spell cast if spell has a mana cost
5583 m_usesMana = true;
5584 }
5585
5586 if (!getSpellInfo()->hasValidPowerType())
5587 {
5588 sLogger.failure("Spell::takePower : Unknown power type {} for spell id {}", getSpellInfo()->getPowerType(), getSpellInfo()->getId());
5589 return;
5590 }
5591
5592 u_caster->modPower(getSpellInfo()->getPowerType(), -static_cast<int32_t>(m_powerCost));
5593}
void sendSpellNonMeleeDamageLog(Object *caster, Object *target, SpellInfo const *spellInfo, uint32_t damage, uint32_t absorbedDamage, uint32_t resistedDamage, uint32_t blockedDamage, uint32_t overKill, bool isPeriodicDamage, bool isCriticalHit)
Definition Unit.cpp:4232
Here is the call graph for this function:
Here is the caller graph for this function:

◆ takeUsedSpellModifiers()

void Spell::takeUsedSpellModifiers ( )

Definition at line 5882 of file Spell.cpp.

5883{
5884 if (m_usedModifiers.empty())
5885 return;
5886
5887 for (auto itr = m_usedModifiers.begin(); itr != m_usedModifiers.end();)
5888 {
5889 auto aurEff = (*itr).first;
5890 // Check for faulty entry
5891 if (aurEff->getAura() == nullptr || (*itr).second)
5892 {
5893 itr = m_usedModifiers.erase(itr);
5894 continue;
5895 }
5896
5897 aurEff->getAura()->removeCharge();
5898 itr = m_usedModifiers.erase(itr);
5899 }
5900}
Here is the caller graph for this function:

◆ unsetAllTargets()

void Spell::unsetAllTargets ( )

Definition at line 5690 of file Spell.cpp.

5691{
5692 m_unitTarget = nullptr;
5693 m_itemTarget = nullptr;
5694 m_gameObjTarget = nullptr;
5695 m_playerTarget = nullptr;
5696 m_corpseTarget = nullptr;
5697}
Here is the caller graph for this function:

◆ update()

void Spell::update ( unsigned long  timePassed)

\ todo: determine which spells can be cast while moving

Definition at line 1271 of file Spell.cpp.

1272{
1273 // Check for moving while casting or channeling
1275 {
1276 // but allow slight error
1277 if (u_caster != nullptr &&
1278 (std::fabs(u_caster->GetPositionX() - m_castPositionX) > 0.5f ||
1279 std::fabs(u_caster->GetPositionY() - m_castPositionY) > 0.5f ||
1280 std::fabs(u_caster->GetPositionZ() - m_castPositionZ) > 0.5f))
1281 {
1282 // TODO: remove this hackfix when movement is sorted out
1283 if (m_spellState == SPELL_STATE_CHANNELING && !getSpellInfo()->hasEffectApplyAuraName(SPELL_AURA_MOD_POSSESS))
1284 {
1285 // Cancel channeled spells which don't have ATTRIBUTESEXE_CAN_MOVE_WHILE_CHANNELING flag
1286 if (getSpellInfo()->getChannelInterruptFlags() & CHANNEL_INTERRUPT_ON_MOVEMENT && !(getSpellInfo()->getAttributesExE() & ATTRIBUTESEXE_CAN_MOVE_WHILE_CHANNELING))
1287 {
1288 cancel();
1289 return;
1290 }
1291 }
1292 ///\ todo: determine which spells can be cast while moving
1293 else if (getSpellInfo()->getInterruptFlags() & CAST_INTERRUPT_ON_MOVEMENT)
1294 {
1295 // Don't cancel on next melee, autorepeat or triggered spells
1296 if (!u_caster->hasNoInterrupt() && !m_triggeredSpell && !getSpellInfo()->isOnNextMeleeAttack() && !getSpellInfo()->isRangedAutoRepeat())
1297 {
1298 cancel();
1299 return;
1300 }
1301 }
1302 }
1303 }
1304
1305 switch (m_spellState)
1306 {
1308 {
1309 m_timer -= timePassed;
1310
1311 if (m_timer <= 0 && !getSpellInfo()->isOnNextMeleeAttack() && !getSpellInfo()->isRangedAutoRepeat())
1312 {
1313 // Skip checks for instant spells
1314 castMe(m_castTime > 0);
1315 }
1316 } break;
1318 {
1319 if (m_timer > 0)
1320 {
1321 if (p_caster != nullptr)
1322 {
1323 // Check if channeled spell is cancelled when turning
1324 if (m_castPositionO != p_caster->GetOrientation() && getSpellInfo()->getChannelInterruptFlags() & CHANNEL_INTERRUPT_ON_TURNING)
1325 cancel();
1326 }
1327
1328 if (timePassed >= static_cast<uint32_t>(m_timer))
1329 m_timer = 0;
1330 else
1331 m_timer -= timePassed;
1332 }
1333
1334 // Channeling finishes
1335 if (m_timer == 0)
1336 {
1337 sendChannelUpdate(0, timePassed);
1338 finish();
1339 }
1340 } break;
1342 {
1343 for (auto hitItr = m_hitEffects.begin(); hitItr != m_hitEffects.end();)
1344 {
1345 auto& hitEff = *hitItr;
1346 if (hitEff.second.travelTime > timePassed)
1347 {
1348 hitEff.second.travelTime -= timePassed;
1349 ++hitItr;
1350 continue;
1351 }
1352
1353 handleHittedEffect(hitEff.first, hitEff.second.effIndex, hitEff.second.damage, true);
1354 hitItr = m_hitEffects.erase(hitItr);
1355 }
1356
1357 for (auto missItr = m_missEffects.begin(); missItr != m_missEffects.end();)
1358 {
1359 auto& missEff = *missItr;
1360 if (missEff.second.travelTime > timePassed)
1361 {
1362 missEff.second.travelTime -= timePassed;
1363 ++missItr;
1364 continue;
1365 }
1366
1367 handleMissedEffect(missEff.second.missInfo, true);
1368 missItr = m_missEffects.erase(missItr);
1369 }
1370
1371 for (auto auraItr = m_pendingAuras.begin(); auraItr != m_pendingAuras.end();)
1372 {
1373 auto& auraEff = *auraItr;
1374 if (auraEff.second.travelTime > timePassed)
1375 {
1376 auraEff.second.travelTime -= timePassed;
1377 ++auraItr;
1378 continue;
1379 }
1380
1381 HandleAddAura(auraEff.first);
1382 auraItr = m_pendingAuras.erase(auraItr);
1383 }
1384
1385 // If all effects and targets have been processed, finish the spell
1386 if (m_hitEffects.empty() && m_missEffects.empty() && m_pendingAuras.empty())
1387 finish();
1388 } break;
1389 default:
1390 break;
1391 }
1392}
@ CAST_INTERRUPT_ON_MOVEMENT
@ CHANNEL_INTERRUPT_ON_TURNING
@ ATTRIBUTESEXE_CAN_MOVE_WHILE_CHANNELING
void cancel()
Definition Spell.cpp:1394
uint16_t hasNoInterrupt() const
Definition Unit.hpp:1235
Here is the call graph for this function:
Here is the caller graph for this function:

◆ wasCastedinDuel()

bool Spell::wasCastedinDuel ( ) const

Definition at line 5659 of file Spell.cpp.

5660{
5661 return duelSpell;
5662}
Here is the caller graph for this function:

◆ writeProjectileDataToPacket()

void Spell::writeProjectileDataToPacket ( WorldPacket data)
private

Definition at line 5405 of file Spell.cpp.

5406{
5407 ItemProperties const* ammoItem = nullptr;
5408#if VERSION_STRING < Cata
5409 if (p_caster != nullptr)
5410 {
5412 if (rangedItem != nullptr)
5413 {
5414 if (getSpellInfo()->getId() == SPELL_RANGED_THROW)
5415 {
5416 ammoItem = rangedItem->getItemProperties();
5417 }
5418 else
5419 {
5420 if (p_caster->getAmmoId() != 0)
5421 {
5422 ammoItem = sMySQLStore.getItemProperties(p_caster->getAmmoId());
5423 }
5424 else
5425 {
5426 // Use Rough Arrow if ammo id is not found
5427 ammoItem = sMySQLStore.getItemProperties(2512);
5428 }
5429 }
5430 }
5431 }
5432 else if (u_caster != nullptr)
5433 {
5434 // Get creature's ranged weapon
5435 // Need to loop through all weapon slots because NPCs can have the ranged weapon in main hand
5436 for (uint8_t i = 0; i <= RANGED; ++i)
5437 {
5438#if VERSION_STRING > TBC
5439 const auto entryId = u_caster->getVirtualItemSlotId(i);
5440#else
5441 const auto entryId = dynamic_cast<Creature*>(u_caster)->getVirtualItemEntry(i);
5442#endif
5443 if (entryId == 0)
5444 continue;
5445
5446#if VERSION_STRING > TBC
5447 // Get the item data from DBC files
5448 const auto itemDBC = sItemStore.lookupEntry(entryId);
5449 if (itemDBC == nullptr || itemDBC->Class != ITEM_CLASS_WEAPON)
5450 continue;
5451
5452 switch (itemDBC->SubClass)
5453 {
5456 // Use Rough Arrow for bows
5457 ammoItem = sMySQLStore.getItemProperties(2512);
5458 break;
5460 // Use Light Shot for guns
5461 ammoItem = sMySQLStore.getItemProperties(2516);
5462 break;
5464 ammoItem = sMySQLStore.getItemProperties(entryId);
5465 break;
5466 default:
5467 break;
5468 }
5469#else
5470 // Get the item data from unitdata
5471 const auto itemData = u_caster->getVirtualItemInfoFields(i);
5472 if (itemData.fields.item_class != ITEM_CLASS_WEAPON)
5473 continue;
5474
5475 switch (itemData.fields.item_subclass)
5476 {
5479 // Use Rough Arrow for bows
5480 ammoItem = sMySQLStore.getItemProperties(2512);
5481 break;
5483 // Use Light Shot for guns
5484 ammoItem = sMySQLStore.getItemProperties(2516);
5485 break;
5487 ammoItem = sMySQLStore.getItemProperties(entryId);
5488 break;
5489 default:
5490 break;
5491 }
5492#endif
5493
5494 // No need to continue if ammo has been found
5495 if (ammoItem != nullptr)
5496 break;
5497 }
5498 }
5499#endif
5500
5501 if (ammoItem != nullptr)
5502 {
5503 *data << uint32_t(ammoItem->DisplayInfoID);
5504 *data << uint32_t(ammoItem->InventoryType);
5505 }
5506#if VERSION_STRING > TBC
5507 else
5508 {
5509 *data << uint32_t(0);
5510 *data << uint32_t(0);
5511 }
5512#endif
5513}
SERVER_DECL WDB::WDBContainer< WDB::Structures::ItemEntry > sItemStore
uint32_t getVirtualItemSlotId(uint8_t slot) const
Definition Unit.cpp:961
Here is the call graph for this function:
Here is the caller graph for this function:

◆ writeSpellMissedTargets()

void Spell::writeSpellMissedTargets ( WorldPacket data)
private

Definition at line 5515 of file Spell.cpp.

5516{
5517 if (u_caster != nullptr && u_caster->isAlive())
5518 {
5519 for (const auto& target : m_missedTargets)
5520 {
5521 *data << uint64_t(target.targetGuid);
5522 *data << uint8_t(target.hitResult);
5523 // Need to send hit result for the reflected spell
5524 if (target.hitResult == SPELL_DID_HIT_REFLECT)
5525 *data << uint8_t(target.extendedHitResult);
5526 }
5527 }
5528 else
5529 {
5530 for (const auto& target : m_missedTargets)
5531 {
5532 *data << uint64_t(target.targetGuid);
5533 *data << uint8_t(target.hitResult);
5534 }
5535 }
5536}
Here is the call graph for this function:
Here is the caller graph for this function:

Friends And Related Symbol Documentation

◆ DummySpellHandler

friend class DummySpellHandler
friend

Definition at line 481 of file Spell.hpp.

◆ DynamicObject

friend class DynamicObject
friend

Definition at line 726 of file Spell.hpp.

Member Data Documentation

◆ add_damage

uint32_t Spell::add_damage
protected

Definition at line 712 of file Spell.hpp.

◆ cancastresult

SpellCastResult Spell::cancastresult = SPELL_CAST_SUCCESS
private

Definition at line 337 of file Spell.hpp.

◆ castedItemId

uint32_t Spell::castedItemId

Definition at line 684 of file Spell.hpp.

◆ chaindamage

uint32_t Spell::chaindamage

Definition at line 665 of file Spell.hpp.

◆ damage

int32_t Spell::damage

Definition at line 679 of file Spell.hpp.

◆ damageToHit

int32_t Spell::damageToHit

Definition at line 683 of file Spell.hpp.

◆ duelSpell

bool Spell::duelSpell = false
protected

Definition at line 160 of file Spell.hpp.

◆ effectPctModifier

float_t Spell::effectPctModifier[MAX_SPELL_EFFECTS]
private

Definition at line 332 of file Spell.hpp.

◆ extra_cast_number

uint8_t Spell::extra_cast_number

Definition at line 685 of file Spell.hpp.

◆ forced_basepoints

std::shared_ptr<SpellForcedBasePoints> Spell::forced_basepoints

Definition at line 245 of file Spell.hpp.

◆ g_caster

GameObject* Spell::g_caster = nullptr
protected

Definition at line 165 of file Spell.hpp.

◆ i_caster

Item* Spell::i_caster = nullptr
protected

Definition at line 166 of file Spell.hpp.

◆ isDurationSet

bool Spell::isDurationSet = false
private

Definition at line 306 of file Spell.hpp.

◆ isEffectDamageStatic

bool Spell::isEffectDamageStatic[MAX_SPELL_EFFECTS]
private

Definition at line 331 of file Spell.hpp.

◆ isForcedCrit

bool Spell::isForcedCrit = false
private

Definition at line 330 of file Spell.hpp.

◆ isTargetDamageInfoSet

bool Spell::isTargetDamageInfoSet = false
private

Definition at line 314 of file Spell.hpp.

◆ m_AreaAura

bool Spell::m_AreaAura

Definition at line 680 of file Spell.hpp.

◆ m_canBeReflected

bool Spell::m_canBeReflected = false
private

Definition at line 300 of file Spell.hpp.

◆ m_caster

Object* Spell::m_caster = nullptr
protected

Definition at line 162 of file Spell.hpp.

◆ m_casterDamageInfo

DamageInfo Spell::m_casterDamageInfo = DamageInfo()
private

Definition at line 312 of file Spell.hpp.

◆ m_casterProcFlags

uint32_t Spell::m_casterProcFlags = 0
private

Definition at line 315 of file Spell.hpp.

◆ m_castPositionO

float_t Spell::m_castPositionO = 0.0f
protected

Definition at line 158 of file Spell.hpp.

◆ m_castPositionX

float_t Spell::m_castPositionX = 0.0f
protected

Definition at line 155 of file Spell.hpp.

◆ m_castPositionY

float_t Spell::m_castPositionY = 0.0f
protected

Definition at line 156 of file Spell.hpp.

◆ m_castPositionZ

float_t Spell::m_castPositionZ = 0.0f
protected

Definition at line 157 of file Spell.hpp.

◆ m_castTime

int32_t Spell::m_castTime = 0
private

Definition at line 124 of file Spell.hpp.

◆ m_charges

int32_t Spell::m_charges

Definition at line 681 of file Spell.hpp.

◆ m_corpseTarget

Corpse* Spell::m_corpseTarget = nullptr
private

Definition at line 208 of file Spell.hpp.

◆ m_critTargets

std::vector<uint64_t> Spell::m_critTargets
private

Definition at line 328 of file Spell.hpp.

◆ m_Delayed

bool Spell::m_Delayed
protected

Definition at line 705 of file Spell.hpp.

◆ m_DelayStep

uint8_t Spell::m_DelayStep
protected

Definition at line 706 of file Spell.hpp.

◆ m_doneTargetProcs

std::set<uint64_t> Spell::m_doneTargetProcs
private

Definition at line 319 of file Spell.hpp.

◆ m_duration

int32_t Spell::m_duration = 0
private

Definition at line 305 of file Spell.hpp.

◆ m_effectRadius

float_t Spell::m_effectRadius[MAX_SPELL_EFFECTS] = { 0.0f }
private

Definition at line 308 of file Spell.hpp.

308{ 0.0f };

◆ m_effectTargets

std::vector<uint64_t> Spell::m_effectTargets[MAX_SPELL_EFFECTS]
private

Definition at line 199 of file Spell.hpp.

◆ m_gameObjTarget

GameObject* Spell::m_gameObjTarget = nullptr
private

Definition at line 206 of file Spell.hpp.

◆ m_glyphslot

uint32_t Spell::m_glyphslot

Definition at line 686 of file Spell.hpp.

◆ m_hitEffects

std::map<uint64_t, HitSpellEffect> Spell::m_hitEffects
private

Definition at line 326 of file Spell.hpp.

◆ m_IsCastedOnSelf

bool Spell::m_IsCastedOnSelf
protected

Definition at line 708 of file Spell.hpp.

◆ m_isEffectRadiusSet

bool Spell::m_isEffectRadiusSet[MAX_SPELL_EFFECTS] = { false }
private

Definition at line 309 of file Spell.hpp.

309{ false };

◆ m_itemTarget

Item* Spell::m_itemTarget = nullptr
private

Definition at line 205 of file Spell.hpp.

◆ m_magnetTarget

uint64_t Spell::m_magnetTarget
protected

Definition at line 710 of file Spell.hpp.

◆ m_missedTargets

std::vector<SpellTargetMod> Spell::m_missedTargets
private

Definition at line 197 of file Spell.hpp.

◆ m_missEffects

std::map<uint64_t, MissSpellEffect> Spell::m_missEffects
private

Definition at line 327 of file Spell.hpp.

◆ m_missilePitch

float Spell::m_missilePitch

Definition at line 721 of file Spell.hpp.

◆ m_missileTravelTime

uint32_t Spell::m_missileTravelTime

Definition at line 722 of file Spell.hpp.

◆ m_pendingAuras

std::map<uint64_t, HitAuraEffect> Spell::m_pendingAuras
private

Definition at line 325 of file Spell.hpp.

◆ m_playerTarget

Player* Spell::m_playerTarget = nullptr
private

Definition at line 207 of file Spell.hpp.

◆ m_powerCost

uint32_t Spell::m_powerCost = 0
private

Definition at line 136 of file Spell.hpp.

◆ m_requiresCP

bool Spell::m_requiresCP = false
private

Definition at line 302 of file Spell.hpp.

◆ m_rune_avail_before

uint8_t Spell::m_rune_avail_before
protected

Definition at line 714 of file Spell.hpp.

◆ m_Spell_Failed

bool Spell::m_Spell_Failed
protected

Spell state's.

Definition at line 704 of file Spell.hpp.

◆ m_spellInfo

SpellInfo const* Spell::m_spellInfo = nullptr
private

Definition at line 236 of file Spell.hpp.

◆ m_spellInfo_override

SpellInfo const* Spell::m_spellInfo_override = nullptr
private

Definition at line 239 of file Spell.hpp.

◆ m_spellState

SpellState Spell::m_spellState = SPELL_STATE_NULL
private

Definition at line 336 of file Spell.hpp.

◆ m_targetConstraint

SpellTargetConstraint const* Spell::m_targetConstraint
protected

Definition at line 215 of file Spell.hpp.

◆ m_targetConstraintCreature

Creature* Spell::m_targetConstraintCreature = nullptr
protected

Definition at line 212 of file Spell.hpp.

◆ m_targetConstraintGameObject

GameObject* Spell::m_targetConstraintGameObject = nullptr
protected

Definition at line 213 of file Spell.hpp.

◆ m_targetDamageInfo

DamageInfo Spell::m_targetDamageInfo = DamageInfo()
private

Definition at line 313 of file Spell.hpp.

◆ m_targetProcFlags

uint32_t Spell::m_targetProcFlags = 0
private

Definition at line 316 of file Spell.hpp.

◆ m_targets

SpellCastTargets Spell::m_targets

Definition at line 535 of file Spell.hpp.

◆ m_timer

int32_t Spell::m_timer = 0
private

Definition at line 125 of file Spell.hpp.

◆ m_triggeredByAura

Aura* Spell::m_triggeredByAura = nullptr
private

Definition at line 340 of file Spell.hpp.

◆ m_triggeredSpell

bool Spell::m_triggeredSpell = false
private

Definition at line 339 of file Spell.hpp.

◆ m_uniqueHittedTargets

std::vector<SpellUniqueTarget> Spell::m_uniqueHittedTargets
private

Definition at line 195 of file Spell.hpp.

◆ m_unitTarget

Unit* Spell::m_unitTarget = nullptr
private

Definition at line 204 of file Spell.hpp.

◆ m_usedComboPoints

int8_t Spell::m_usedComboPoints = 0
private

Definition at line 303 of file Spell.hpp.

◆ m_usedModifiers

std::map<AuraEffectModifier const*, bool> Spell::m_usedModifiers
private

Definition at line 334 of file Spell.hpp.

◆ m_usesMana

bool Spell::m_usesMana = false
private

Definition at line 138 of file Spell.hpp.

◆ p_caster

Player* Spell::p_caster = nullptr
protected

Definition at line 164 of file Spell.hpp.

◆ ProcedOnSpell

SpellInfo const* Spell::ProcedOnSpell

Definition at line 534 of file Spell.hpp.

◆ pSpellId

uint32_t Spell::pSpellId

Definition at line 533 of file Spell.hpp.

◆ u_caster

Unit* Spell::u_caster = nullptr
protected

Definition at line 163 of file Spell.hpp.


The documentation for this class was generated from the following files: